# PalDock Knowledge Base > Generated: 2026-08-14T20:06:06+02:00 > Items: 142 | Size: 491 KB | Tokens: ~131.9k > Characters: 501068 (419279 no spaces) | Words: 0 | Sentences: 4599 | Paragraphs: 4858 | Lines: 10259 > Metrics cover everything below this header. > Sections are wrapped in and markers. Articles follow the order of the table of contents. ## Contents - **Getting started** - Start here - Basic visual cues - One Account, Multiple Workspaces - Dashboard - Conversion -> Commission -> Transaction - First steps to get started - Prospect + Sale vs Pending Sale - Test the Offers - See first results - Tracking guide - Categorization - **User Management** - About User management - Affiliates - Advertisers - Admins - **Reports and Logs** - About Reports and Logs - Highlights - Show rows in chart - Advanced columns - Filters - Result Type Filter - Reporting time basis - Performance reports - Pingtree reports - Logs - Transactions report - Import - Export - Columns explained - **Offers** - About Offers - Allowed Delivery method - Advertiser - Offer organization - Currency - Offer description - Offer Access - Affiliate link - Deep link - Embeddable form - API integration - Pingtree Distribution - Refuse leads - Process refused leads - External Final Page - Data feeds - Affiliate ID rewrite - Pre-filling fields - Auto submit - Offer and Pingtree Filters - Lead and Click Capping - **Commissions** - About commissions - How the commission is selected - Commission status - Commission conditions to create Transactions - Multiple Commissions for the Same Conversion Type - Auto-approve transactions - Auto-set transaction result - Transaction type - Recurrence type - Deduplication based on advertiser's ID - Commission amount - Display amount - Commission detail - Commission schedule - Commission group - Commission order - Commission ID - **Tracking** - About Tracking - Conversion IDs explained - Tracking processing - Conversion type - Tracking pixel - How to set up pixel tracking - Tracking S2S Postback - Tracking API - Manual Tracking and Transaction Import - Tracking parameters - Tracking by vouchers - Tracking and Conversion Logs - Affiliate postback - Origin Deduplication - Update pixel - Tracking errors and reasons - **Structures** - About structures - Local, Global and Custom fields - Field settings - Field types - Field validation - Modification - AutoComplete - Translations - Form structure - User structure - Feed structure - Multiple Structures for Offers and Integrations - **Connection Creator** - About connection creator - Where Connection Creator is used - Editor - How to integrate anything - Connection Creator in Integration - Connection Creator in Structures - Connection Creator in Tracking - Library of Integrations - Reject reason - Limits and timeouts - **Element types** - List of nodes - Start - Connections with Conditions - Modify in Connection Creator - HTTP node - Field format - HTTP Signature - Set - Wait - Breaker - Webhook - End trigger - Set Event - Mirror - **General tools** - Condition Operators and values - Group changes - Parameters - **Modifications** - List of modifications - to-string - to-float - to-bool - to-int - set value - math - unix - prefix - postfix - first-regex-match - do-not-send - format-date - modify-date - to-base64 - from-base64 - regex-replace - urlencode - urldecode - **Settings** - About settings --- # Getting started ## Start here This section takes you from an empty workspace to one with working tracking and real numbers in it. Nothing here needs to be finished in one sitting. PalDock ships with defaults for almost everything, so the usual route is to build the whole chain quickly, test it, and fill in the detail afterwards. It works the same whether you are a network, an advertiser running your own program, or an affiliate with a workspace of your own. What differs is which numbers you care about. ##### Understand the ground rules - **[Basic visual cues](https://paldock.com/knowledge-base/basic-visual-cues/)**: the layout, the workspace picker, and why the background is sometimes green. - **[One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/)**: what belongs to a person’s PalDock account and what belongs to your workspace. This is the one that explains why you cannot change a partner’s email. - **[Conversion, Commission, Transaction](https://paldock.com/knowledge-base/conversion-commission-transaction/)**: three words used constantly in PalDock. Read this before the setup pages. ##### Set it up - **[First steps to get started](https://paldock.com/knowledge-base/first-steps-to-get-started/)**: currency, the first offer, commissions, and tracking. The main setup page. - **[Prospect + Sale vs Pending Sale](https://paldock.com/knowledge-base/prospect-sale-vs-pending-sale/)**: whether to pay for one step or two. Decide it per offer, before the commissions are built. - **[Tracking guide](https://paldock.com/knowledge-base/tracking-guide/)**: which tracking method to use, which identifier the advertiser must send back, and what to hand them. ##### Check that it works - **[Test the Offers](https://paldock.com/knowledge-base/test-the-offers/)**: click your own link, submit your own lead, and watch the transaction move through its results. - **[See first results](https://paldock.com/knowledge-base/see-first-results/)**: which four numbers everything else is built from, and why a report can look empty on day one when nothing is wrong. ##### Keep it tidy - **[Dashboard](https://paldock.com/knowledge-base/dashboard/)**: the daily view, and where partners are approved and payouts handled. - **[Categorization](https://paldock.com/knowledge-base/categorization/)**: countries, categories, and tags. They look cosmetic and they are what you filter and group reports by later, so set them as you go. ##### Where to go next Once traffic is flowing, the rest of the knowledge base covers it in depth: [Offers](https://paldock.com/knowledge-base/topics/offers/), [Commissions](https://paldock.com/knowledge-base/topics/commissions/), [Tracking](https://paldock.com/knowledge-base/topics/tracking/), and [Reports and Logs](https://paldock.com/knowledge-base/topics/reports-and-logs/). When something does not appear where you expect it, the answer is almost always in the [logs](https://paldock.com/knowledge-base/logs/). They record every click, lead, conversion, and request, with the reason attached. --- ## Basic visual cues PalDock keeps the same layout everywhere, so once you can read one screen you can read all of them. ##### The workspace picker The **top left corner** shows which workspace you are in. Switch it and everything changes with it: data, reports, offers, and partners. Nothing is shared between workspaces except the accounts themselves. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). ##### Layout Three areas, on every screen: - **Main menu**, the left sidebar. Access to every module. It does not change. - **Top tabs**, the horizontal menu. Context for the module you are in, and the tabs differ between preview and edit. - **Top right controls**. Workspace, profile, search, payouts, and adding new items. ##### Preview and edit PalDock has two modes, and the background colour tells you which one you are in. - **Preview** is **grey**. You are looking, not changing. Data, offers, and settings are visible but nothing you do here saves. - **Edit** is **green**. You are changing something. Details, settings, and tracking configuration are editable. The colour is the fastest way to answer why a change did not stick. If the background is grey, it was never being saved. ##### Icons that mean the same thing everywhere Tables share a set of controls, and each icon does the same job wherever you meet it: - **Column icon**: choose which columns are shown. See [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/). - **Layer icon**: add a secondary grouping. See [Performance reports](https://paldock.com/knowledge-base/performance-reports/). - **Target icon**: switch the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/). - **Filter button**: open the large filter. See [Filters](https://paldock.com/knowledge-base/filters/). - **Checkbox icon**: select or clear all rows, which is what makes rows plottable in the chart and exportable on their own. - **Trash icon**: remove, always with a confirmation step. --- ## One Account, Multiple Workspaces PalDock is an ecosystem, not a single affiliate program. Everybody in it, partners, advertisers, and networks, has one **PalDock account**, and that account connects to as many **workspaces** as they work with. When somebody registers, the account is created first and immediately connected to the workspace they registered through. Joining a second workspace later does not create a second account. ##### What belongs to the account This data follows the person everywhere and is changed only by them: - **Email, nickname, and password** - **Billing details** - **Global fields**, the shared profile data every workspace can read A change made once propagates to every workspace that person belongs to. ##### What belongs to the workspace This data is yours and nobody outside your workspace sees it: - **Custom fields** you defined in your [user structure](https://paldock.com/knowledge-base/user-structure/) - **Country, language, category, and tags** you assigned - **[Commission group](https://paldock.com/knowledge-base/commission-group/)** and the admin who manages the account - **Offer access and permissions** - **Results, transactions, and balances** See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). ##### What this makes easy - **One registration.** From there a partner can browse the catalogue of offers to promote, and an advertiser can find partners to promote theirs. - **Joining you is close to one click.** Everything global is already filled in. The partner only completes the custom fields you ask for, which is a good reason to ask for few. - **Data stays current.** A partner who changes their company address changes it once, not once per program. ##### What it costs you - **You cannot change a partner’s basic data.** Nickname, email, and password belong to the account, and no workspace permission overrides that. - **The same goes for billing information.** Only the account owner can change it, which matters when an invoice comes back with the wrong details. The fix is with them, not with you. This applies to your own team as well. Admins have PalDock accounts too, so their name and email are theirs, not yours to edit. See [Admins](https://paldock.com/knowledge-base/admins/). ##### Moving between workspaces - Pick the workspace you are working in from the **top left corner**. Everything on screen, data, reports, offers, and partners, switches with it. - Partners manage which workspaces they belong to under the **user icon in the top right**. Whether new registrations are active straight away and whether your program is listed publicly in the catalogue are workspace settings. See [Settings](https://paldock.com/knowledge-base/about-settings/). --- ## Dashboard The Dashboard is the first screen after logging in. It is a summary of the workspace plus the handful of actions you take most often, so the everyday routine does not require opening a report at all. What you see depends on who you are. ##### For admins ###### The numbers The row of [Highlights](https://paldock.com/knowledge-base/highlights/) at the top shows your key metrics for the selected period. This is also the place where Highlights are added and removed, and the set you choose applies wherever they appear. Below them, a short table gives the last few days and the most recent conversions. Enough to notice that something stopped, without going into [reports](https://paldock.com/knowledge-base/topics/reports-and-logs/). ###### Top offers and affiliates Your best performing offers and partners, with the option to **pin** the offers you watch most so they stay at the top. ###### Onboarding New affiliates and advertisers waiting for approval appear here, and you can grant them access to the workspace or to specific offers without leaving the page. Whether they wait for you at all is a workspace setting. See [Settings](https://paldock.com/knowledge-base/about-settings/). ###### Payouts Affiliate payout requests and advertiser invoices are approved from the Dashboard, next to the numbers they came from. ##### For affiliates - **Their results** for the selected period, in the same Highlights format. - **Tracking links.** An affiliate generates a link for any offer they have access to directly from the Dashboard, without going through the offer. - **Payout breakdown by result**, so they can see what was approved, what is still pending, and which transactions each amount came from. ##### The period Everything on the Dashboard follows the date range you pick, and it respects the [result type filter](https://paldock.com/knowledge-base/result-type-filter/) and the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) the same way reports do. A Dashboard that disagrees with a report is almost always one of those three set differently. --- ## Conversion -> Commission -> Transaction Three words come up constantly in PalDock, and everything else makes more sense once they are clear. - A **conversion** is something that happened. - A **commission** is a rule about what it is worth. - A **transaction** is the money that came out of it. ##### Conversion A conversion is a recorded event with no money attached. It reaches PalDock in one of two ways: - **Created by PalDock**: clicks, leads, and sends. These happen because somebody clicked a link or submitted a form. - **Received through tracking**: prospects, sales, and any custom type you define. These are reported by the advertiser, through a pixel, a postback, the Tracking API, or a manual import. On its own a conversion is a performance metric. It appears in reports, it counts towards your click and lead numbers, and it pays nobody. See [Conversion type](https://paldock.com/knowledge-base/conversion-type/). ##### Commission A commission is the rule that turns a conversion into a payout. It decides: - **Which conversions it applies to**, by offer, advertiser, conversion type, source, and channel. - **How much** is paid, to your partner and by your advertiser. - **What kind of transaction** is created. See [Transaction type](https://paldock.com/knowledge-base/transaction-type/). Without a matching commission, nothing is paid. The conversion is still recorded, it simply produces no transaction. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Transaction A transaction is a conversion with a payout and a result: **pending**, **approved**, or **rejected**. It has two sides, what you pay the affiliate and what the advertiser pays you, and they are synchronised. Approving one approves the other, so the two can never disagree. ##### How it fits together A visitor clicks an affiliate link, which creates a **click**. They fill in a form, which creates a **lead**. Days later the advertiser confirms the order, which creates a **sale**. Three conversions, one journey. Your commission says a sale on this offer is worth 40 to the affiliate and 55 from the advertiser, so the sale produces a **transaction**. The click and the lead stay as they are, counted in reports and paid for by nobody, unless you have commissions for them too. ##### When there is no transaction A conversion exists but no payout appeared. The usual reasons: - No commission matches that conversion type. - The commission is inactive or outside its active period. - The [recurrence limit](https://paldock.com/knowledge-base/recurrence-type/) was reached. - The conversion was [deduplicated](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) on the advertiser’s external ID. The conversion log tells you which one it was. See [Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/). --- ## First steps to get started This page takes you from an empty workspace to one that records clicks, leads, and conversions. Read it once before you start clicking, because two of the decisions here are easier to make now than to change later. ##### Decide two things first ###### Workspace currency One currency for the whole workspace. Reports convert every amount into it and show one total, while transactions, balances, and invoices stay in the currency of the offer they belong to. See [Currency](https://paldock.com/knowledge-base/currency/). Users cannot pick their own. Everybody in the workspace sees the workspace currency. It can be changed later, but the change recalculates historical report values, so it is not something to do casually. Pick the currency you invoice in. ###### Workspace language The workspace has a default language, and each registered user can switch to their own. Nothing depends on it beyond what people read. ##### Use the defaults A new workspace comes with prepared defaults, including a default advertiser and a default commission group. They exist so you can build the whole chain now and fill in the detail later. Everything below can be created without completing every field. Offers, commissions, and accounts all accept the minimum and let you come back. ##### Step 1: create an offer Most settings are already sensible. What you actually need to decide: ###### Commission amounts Two numbers, what your partner gets and what the advertiser pays you. - **A network** earns the difference between the two. - **An advertiser** is setting a maximum CPA, which the profit per partner is measured against. - **An affiliate with their own workspace** can set both the same. It is for you and any sub-affiliates later. ROI and the other derived metrics come from the difference between them. See [Commission amount](https://paldock.com/knowledge-base/commission-amount/). A commission is a rule saying when a transaction is created from a conversion. Some conversions PalDock creates itself, such as clicks and leads. Others arrive through tracking, such as prospects and sales. See [Conversion, Commission, Transaction](https://paldock.com/knowledge-base/conversion-commission-transaction/). ###### Commission group and advertiser - Stay with the default [commission group](https://paldock.com/knowledge-base/commission-group/) for now. Custom groups are how you pay different partners differently, and affiliates can be assigned to them later. - **Assign the correct advertiser** before you go live. The default advertiser gets you moving, but conversion tracking depends on the real one being there. ###### Promotion method Choose affiliate link, iframe, or API. See [Allowed Delivery method](https://paldock.com/knowledge-base/allowed-delivery-method/). - **Affiliate link**: paste the advertiser’s URL and add the tracking parameter **`pcid`**. It carries the Origin ID of the click, which is what the advertiser sends back with the conversion. See [Affiliate link](https://paldock.com/knowledge-base/affiliate-link/). - **iframe**: configure the [form structure](https://paldock.com/knowledge-base/form-structure/) and pick a design. The defaults work to start with. - **API**: configure the form structure as well. The API does not deliver anything until the offer has distribution channels paired with an integration, which you can add later. See [API integration](https://paldock.com/knowledge-base/api-integration/). Save the offer. ##### Step 2: set up tracking The minimum is a postback from the advertiser, with a pixel as backup. Relying on one method means a misconfiguration on their side costs you conversions. - **Postback**: in **Tracking, Incoming Postback**. Generate the documentation and send it to the advertiser so they call the right URL with the right parameters. See [Tracking S2S Postback](https://paldock.com/knowledge-base/tracking-s2s-postback/). - **Conversion pixel**: in **Settings, Tracking, Conversion types and pixels**. Pick the conversion type, prospect, sale, or your own, and the **create** action. See [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/). - **Update pixel**: same place, **update** action. This is what adds cookie and URL data, such as Google or Meta identifiers, to a lead that already exists. See [Update pixel](https://paldock.com/knowledge-base/update-pixel/). Whatever method the advertiser uses, they have to send an identifier. The **Origin ID**, the value your link carried as `pcid`, or their own **external ID** together with the **advertiser ID**. Without one of those, a conversion cannot be matched to anything. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). They can also send more, such as a **value** for percentage payouts, or a **transaction type** to separate prospects from sales. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). If affiliate links are all you need, you are done here. ##### Step 3: build the integration Only for iframe and API, where PalDock has to deliver the lead somewhere. It is a good moment for it, since you are waiting on the advertiser anyway. First, update the default form structure or create one matching the data you want to collect and pass on, then adjust the form design. Then create the integration in the Integrations section. It works like Zapier or Make: add nodes, connect them, apply conditions and modifications, and build against the advertiser’s API documentation. See [How to integrate anything](https://paldock.com/knowledge-base/how-to-integrate-anything/). Four things the integration has to define: - **Which request prechecks the lead**, and what response means it may continue. Optional. - **Which request sends the lead**, and what response means it was accepted. Required. - **Where the advertiser’s external ID is in the response.** Store it. Without it a later postback has nothing to match against, and you need it whenever they cannot return the Origin ID. - **Where the redirect URL is**, if the customer should be sent on. Optional. ##### Then test it Do not wait for real traffic to find out whether it works. See [Test the Offers](https://paldock.com/knowledge-base/test-the-offers/), and when something does not appear, the [logs](https://paldock.com/knowledge-base/logs/) tell you where it stopped. --- ## Prospect + Sale vs Pending Sale In lead generation there are two ways to model the same journey, and the one you pick decides how many transactions exist and when your partner gets paid. - **Two events**: a prospect and a sale, each paid separately. - **One event with two results**: a sale that starts pending and is approved or rejected later. You can mix them across the workspace, offer by offer. The question is not which is better, it is whether the two steps are worth paying separately for. ##### Prospect and Sale Two conversions, two transactions, two payouts. Use it when both steps have value to you. Common in finance and insurance, where a completed application is worth paying for whether or not the loan is eventually taken. - The prospect creates a transaction under a **CPL** commission. - The sale creates a second one under a **CPS** commission. - Both can carry their own conditions, amounts, and results. The partner sees the first payout soon after sending the lead, which matters when you are competing for their traffic. See [Transaction type](https://paldock.com/knowledge-base/transaction-type/). ##### Pending Sale and Approved Sale One conversion, one transaction, one payout that changes state. Use it when only the finished sale is worth anything. Common in e commerce, where an order can be cancelled or returned and paying on the order itself would mean clawing money back. - The sale arrives and the transaction is created as **pending**. - The advertiser confirms or rejects it later, and the same transaction moves to **approved** or **rejected**. Nothing new is created along the way. The transaction and its payout follow the advertiser’s decision. See [Auto-set transaction result](https://paldock.com/knowledge-base/auto-set-transaction-result/). ##### Which to choose - **Two steps that are each worth money**: prospect and sale. - **One outcome that needs checking first**: pending and approved sale. The practical difference for your partner is when they see the money and how stable their reports look. Two events pay earlier and produce more rows. One event pays later and moves numbers between days as results are decided, which is worth knowing before they ask why yesterday changed. See [Reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/). ##### It does not have to be either Conversion types are not limited to prospect and sale. You can define your own for the steps that matter in your vertical, and pay on them the same way. A pingtree offer might record a verified lead, a signed contract, and a first payment as three separate types. See [Conversion type](https://paldock.com/knowledge-base/conversion-type/). --- ## Test the Offers Test the offer before real traffic reaches it. The steps differ depending on how the offer is promoted, but all three end the same way, with a transaction moving through its results. ##### Before you start Testing runs into deduplication, which is working correctly and looks like a bug. - **Repeated clicks from the same machine collapse into one.** Change network or browser between attempts, or wait out the window. - **Repeated leads with identical data are refused.** Vary the form data. See [Origin Deduplication](https://paldock.com/knowledge-base/deduplication/). ##### Testing an affiliate link - Open the offer and click **Preview Offer**, then the **Link** tab. - Choose the affiliate the link should belong to. The default one is fine. - Open the generated link. That creates a **click**. The click gets an **Origin ID**, carried in the URL as `pcid`. You can read it from the URL, unless the advertiser strips it, and you will always find it in the click log. On the advertiser’s site, complete whatever the offer is about, a form or a purchase. That is what creates the record on their side and makes them fire a pixel or a postback back to you. ##### Testing an iframe - Open the offer and click **Preview Offer**, then the **iframe** tab. - Choose the affiliate. The default one is fine. - Copy the code, embed it on a page of yours, open it, fill the form in, and submit. That creates a **lead**. The lead gets its own **Origin ID**, which you will find in the lead log. After submitting you may see processing and then land on the advertiser’s site to finish the flow. Once the advertiser accepts the lead it appears in their system, and from there the conversion comes back to you the same way as with a link. ##### Testing the API - Open the offer and click **Preview Offer**, then the **API** tab. - Choose the affiliate to get the API token. The default one is fine. - Copy the endpoint URL, build the request in Postman or any API client using the documentation shown on the offer, and send it. That creates a **lead**. Read the response and follow the URL it returns to continue. From there it behaves exactly like the iframe test. See [API integration](https://paldock.com/knowledge-base/api-integration/). ##### Testing the results However the conversion arrived, it usually lands as **pending**, because the advertiser does not know yet whether it will stand. If it matches your commission conditions, a transaction is created with that result. Ask the advertiser to fire the same postback twice more: - Once with the result **approved** - Once with the result **rejected** The transaction should move from pending to approved, then from approved to rejected. That confirms all three results are handled and that updates find the right conversion rather than creating new ones. There is a simpler setup for lead based offers. Configure the commission to create the transaction as soon as the advertiser accepts the lead, and no pending postback is needed at all. See [Auto-set transaction result](https://paldock.com/knowledge-base/auto-set-transaction-result/). ##### When nothing appears Work backwards through the [logs](https://paldock.com/knowledge-base/logs/): - **No click or lead**: the click or lead log. If the row is not there, it never reached PalDock. - **The lead is there but never reached the advertiser**: the integration log, one entry per request. - **The advertiser says they sent a conversion**: the tracking log. If the request is not there it never arrived, and if it is, the result says what happened to it. See [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). - **The conversion is there but no transaction**: the conversion log, then the commission. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). --- ## See first results As soon as you start testing, numbers appear on the [Dashboard](https://paldock.com/knowledge-base/dashboard/) and in [reports](https://paldock.com/knowledge-base/topics/reports-and-logs/). Four columns carry everything else. - **Clicks**: traffic through affiliate links. - **Leads**: forms submitted through an iframe or the API. - **Transactions**: what a commission created from a conversion. - **Costs** and **Revenues**: what you pay and what you are paid, with **Profit** as the difference. Every other metric in PalDock is derived from these. EPL, CPC, ROI, and the rest are all ratios of the same four numbers. See [Columns explained](https://paldock.com/knowledge-base/columns-explained/). ##### Clicks and leads count what was accepted The click and lead columns hold what PalDock processed. Anything refused on arrival, whether it failed validation, was filtered out, or was a duplicate, is not in them. It is not lost either, it is in the [logs](https://paldock.com/knowledge-base/logs/) with the reason. That is why three different lead numbers exist: - **Gross leads**: everything that arrived. - **Leads**: what was accepted and counted. - **Unique leads**: how many were the first from that person in the product. Your own numbers will usually be higher than the ones here, because two events on your side can resolve to one lead. See [Origin Deduplication](https://paldock.com/knowledge-base/deduplication/). ##### Why the numbers may look wrong at first Three settings change what a report says, and all three have defaults that surprise people on day one. - **The [result type filter](https://paldock.com/knowledge-base/result-type-filter/)** starts on approved only. Transactions your advertiser has not decided yet are not counted, so fresh traffic can show leads and no revenue. - **The [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/)** starts on origin time. A sale confirmed today is reported back on the day its lead arrived, so yesterday keeps changing. - **The date range** is whatever the picker says. Test conversions arriving late land outside a narrow range. A report that looks empty is far more often one of these than a broken setup. If you want to see everything, set the result filter to all three and widen the range. ##### Where to go next - **A number looks wrong**: check the three settings above, then [Columns explained](https://paldock.com/knowledge-base/columns-explained/). - **Something is missing entirely**: the [logs](https://paldock.com/knowledge-base/logs/). - **A conversion exists but no payout came out of it**: the conversion log, then [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). --- ## Tracking guide Tracking is how conversions get into PalDock. This page is the overview: which method to use, which identifier to send, and what to hand your advertiser. Every section links to the page that covers it properly. **The short version.** Put the initiation pixel on every page and the conversion pixel on the confirmation page. Add an S2S postback as a cookie free backup. If you send leads through the API or an iframe, most of this gets simpler, because PalDock already knows the lead. ##### The methods - **[Pixel](https://paldock.com/knowledge-base/tracking-pixel/)**: fires in the browser on the advertiser’s confirmation page. Quick to deploy, depends on cookies, can be blocked. - **[S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/)**: sent server to server by the advertiser. Cookie free and reliable. - **[Tracking API](https://paldock.com/knowledge-base/tracking-api/)**: PalDock calls the advertiser to ask about a conversion, or forwards results out. - **[Manual import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/)**: upload conversions yourself when nothing automated is available. Combine at least two. A pixel and a postback together mean a blocked pixel does not cost you the conversion, and PalDock keeps one conversion rather than two. See [Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/). ##### Quick start - **Initiation pixel** on every page. It reads the identifier from the URL and stores it for your attribution window. - **Conversion pixel** on the confirmation page only. It creates the conversion and attributes it to the affiliate whose click was stored. - **S2S postback** from the advertiser’s system, as the backup that works when the browser does not. Steps 1 and 2 get you live. Step 3 is what makes attribution hold up. See [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/). ##### Which identifier to send This is the decision that everything else depends on. A conversion that carries no usable identifier cannot be matched to anything. - **Origin ID.** The ID of the click or lead that started the journey. Your affiliate link carries it as **`pcid`**, and the advertiser sends it back as `origin_id`. One value, two names. - **External ID with Advertiser ID.** The advertiser’s own order ID. On its own it is not unique, in combination with the advertiser it is. This is the pairing to insist on when the offer uses a [Pingtree](https://paldock.com/knowledge-base/distribution/), because several channels share one Origin ID. - **Conversion ID.** The ID of the conversion itself. Used for updating a specific conversion when nothing else addresses it. Ask for the external ID even when the Origin ID is being sent. It costs the advertiser nothing and it is what saves you when the pixel is blocked or the click ID is stripped. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### More than one commission on a type When several commissions exist for the same conversion type, the request has to say which one it means, through **`commission_id`**. Without it, the first commission in order for that type is used. See [Commission ID](https://paldock.com/knowledge-base/commission-id/). ##### Cookie consent A pixel stores the click ID in the browser, so consent rules apply to it. - **No consent obligation, or the cookie counts as essential**: a pixel only setup is enough to start. - **Consent required**: fire the pixel in the storage mode that matches the answer, and always send the S2S postback as well. Consent is granted in roughly two thirds of sessions, so a pixel only setup silently loses the rest. One trap worth knowing before you build anything: **localStorage and sessionStorage are not shared across subdomains.** If the homepage is on the main domain and checkout on a subdomain, only a cookie carries the identifier across. See [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/). ##### Sending leads through iframe or API When the lead comes through PalDock in the first place, tracking is simpler. The lead already exists, so nothing has to be attributed after the fact. What you still need is the advertiser’s external ID stored from their response, so a later postback can find the conversion. See [Connection Creator in Integration](https://paldock.com/knowledge-base/connection-creator-in-integration/). ##### What to give your advertiser Everything they need is generated for you in **Tracking, Incoming Postback**, and on the offer’s Tracking tab. Send them: - The **URL** to call, and when to call it. - Which **identifier** to send back, and that it should be returned exactly as received. - The **conversion type**, so a prospect does not arrive as a sale. - The **result**, and whether they will update it later. - Anything else the commission needs, such as a **value** for percentage payouts. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). If the advertiser cannot change their parameter names to match yours, they do not have to. A scenario on the postback maps their names onto PalDock’s, using `postback_id` in the request. See [Connection Creator in Tracking](https://paldock.com/knowledge-base/connection-creator-in-tracking/). ##### When it does not work - **The request never arrived**: the tracking log is empty for it. Check the pixel, the CSP, or their firewall. - **The request arrived but did nothing**: read the result. See [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). - **The conversion exists but there is no payout**: the conversion log, then [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). Full detail on every method is in the [Tracking](https://paldock.com/knowledge-base/topics/tracking/) section. --- ## Categorization Any entity in a workspace can be classified: affiliates, advertisers, offers, and more. Three ways to do it. - **Country**, single select - **Category**, single select - **Tags**, multi select Categories and tags are yours to define. The country list is fixed. ##### What categorisation is for It is not decoration. Country, category, and tags are **filters and grouping dimensions in every report**, which is what makes them worth setting when an entity is created rather than later. Backfilling tags across two hundred affiliates so you can compare them by type is a bad afternoon. They also decide where your offers and your program appear in the PalDock catalogue, which is how partners and advertisers find each other. See [Settings](https://paldock.com/knowledge-base/about-settings/). ##### Global entities An entity with no country is treated as **Global**. It appears whatever country you filter by, rather than disappearing from every filter. That is usually what you want for an offer that runs everywhere. Set a country when the entity genuinely belongs to one market, because a country set wrongly is worse than one left empty. ##### Choosing between category and tag - **Category** is one value, the main classification. What kind of thing this is. - **Tags** are many, and are for everything else. How a partner works, which campaign an offer belongs to, which team looks after it. If you find yourself wanting two categories, that is what tags are for. ##### Example values These are the categories we use in the offer and partner marketplace. Yours do not have to match. **Offers** - Adult - Baby - Beauty - Business - Education - Electronics - Fashion - Finance - Food - Health - Hobbies - Home - Languages - Lifestyle - Media - Mobility - Pets - Real Estate - SaaS - Shopping - Sports - Travel **Partners** - Cashback - Comparison - Content - Coupon - Email - Influencer - Leadgen - Mobile App - Network - Paid media - Product Catalog --- # User Management ## About User management User Management is where you decide who is in your workspace and what they are allowed to do. There are three kinds of people in it. - **[Affiliates](https://paldock.com/knowledge-base/affiliates/)**: the partners who promote your offers and get paid for the traffic they bring. - **[Advertisers](https://paldock.com/knowledge-base/advertisers/)**: the companies whose offers you run and who pay you for the results. - **[Admins](https://paldock.com/knowledge-base/admins/)**: your own team, with permissions deciding how much of the workspace each of them sees. ##### One account, many workspaces Nobody registers twice in PalDock. A person or a company has one account, and that account connects to as many workspaces as they work with. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). That splits their data in two: - **Global fields** belong to the account. Email, nickname, billing details. They follow the user everywhere, and only the user can change them. A change propagates to every workspace they are in. - **Custom fields** belong to your workspace. You define them, you can edit them, and nobody else sees them. For a partner who already has a PalDock account, joining you is one click and the global fields are already filled in. The only thing left is whatever custom fields you ask for, which is a good reason to ask for few. See [Local, Global and Custom fields](https://paldock.com/knowledge-base//local-versus-global-fields/). ##### How people get in Three routes, for affiliates and advertisers alike: - **They register themselves** through your registration form. What that form asks for is set by the [user structure](https://paldock.com/knowledge-base/user-structure/). - **You invite them** by email. - **You add them manually.** Email and nickname are enough. They fill in the rest when they log in. Whether a new registration is live immediately or waits for you is a workspace setting, along with whether your program is listed publicly in the catalog. See [Settings](https://paldock.com/knowledge-base/about-settings/). Admins are different. You create subaccounts for colleagues and assign them permissions, and they do not self-register. ##### What each type can see Partners work inside the same interface you do, with their own data only. - **Affiliates** see their offers, their traffic, and what they earn. What you pay them is labelled Revenue on their side. They are never shown which channel bought a lead. - **Advertisers** see the offers they own and what they pay. What they pay is labelled Costs on their side, and they see nothing about your affiliates. - **Admins** see what their permissions allow. An admin assigned to manage specific partners sees only the results of those partners. See [Transactions report](https://paldock.com/knowledge-base/transactions-report/) for how columns change per role, and [Filters](https://paldock.com/knowledge-base/filters/) for what a partner can and cannot filter by. ##### Organising accounts Whatever the type, an account can be categorised by **country**, **language**, **category**, and **tags**. Those are not decoration. They are filters and grouping dimensions in every report, which is what makes them worth setting when the account is created rather than later. Two settings do more than organise: - **[Commission group](https://paldock.com/knowledge-base/commission-group/)** on an affiliate decides which commissions apply to them. It is how you pay different partners differently for the same offer. - **Management** assigns an admin to an affiliate or an advertiser. That admin then sees only the accounts they manage. Access can be suspended or removed without deleting anything. The account keeps existing in PalDock and in its other workspaces, it simply stops having access to yours. --- ## Affiliates Affiliates are the partners who promote your offers and get paid for what they bring. This is where you add them, organise them, and decide what they are paid. ##### Adding an affiliate Three routes into your workspace: - **They register themselves** through your registration form. - **You invite them** by email. - **You add them manually.** Whether a new partner is active straight away or waits for your approval is set in [Settings](https://paldock.com/knowledge-base/about-settings/). ###### Adding one manually Two fields are enough: - **Email** - **Nickname** Everything else the partner fills in when they first log in, and it appears in the affiliate detail from then on. If the email already belongs to a PalDock account, you are told so, and the email is the only thing you need. The rest of that person’s data already exists and comes with them. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). ###### Self-registration The registration form is yours to define, through the [user structure](https://paldock.com/knowledge-base/user-structure/). It can ask for two kinds of fields. - **Global fields** belong to the PalDock account. Prefer these. For a partner who already has an account they are pre-filled, so signing up is close to instant. You cannot edit them, only the affiliate can, and their changes propagate to every workspace they are in. - **Custom fields** belong to your workspace. You define them and you can edit them later in the affiliate detail. Every custom field you add is one more thing standing between a partner and a finished registration, so ask for what you actually need. See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). ##### Commission group The [commission group](https://paldock.com/knowledge-base/commission-group/) decides which commissions apply to this affiliate. Use the default group, or create a new one in the [Commissions](https://paldock.com/knowledge-base/topics/commissions/) section. This is how you pay two partners differently for the same offer, so it is worth setting when the account is created rather than after the first payout. ##### Management Assign an admin to the affiliate. That admin sees the results of the partners they manage and nobody else’s. See [Admins](https://paldock.com/knowledge-base/admins/). ##### Categorisation Affiliates can be classified by **country**, **language**, **category**, and **tags**. These are filters and grouping dimensions in every report, so consistent tagging is what later lets you compare a whole group of partners rather than picking them out one by one. ##### What the affiliate sees An affiliate logs into the same interface you do, restricted to their own data. - Their offers, their traffic, and their transactions. - What you pay them is labelled **Revenue** on their side. - They are never shown which channel bought a lead, through a column, a filter, or a grouping. Whether they can see lead data at all, rather than only counts and payouts, is a workspace setting. See [Settings](https://paldock.com/knowledge-base/about-settings/). --- ## Advertisers Advertisers are the companies whose offers you run and who pay you for the results. This is where you add them and organise them. What they pay is defined on the [offer](https://paldock.com/knowledge-base/advertiser/) and its [commissions](https://paldock.com/knowledge-base/topics/commissions/), not here. ##### Adding an advertiser Three routes into your workspace: - **They register themselves** through your registration form. - **You invite them** by email. - **You add them manually.** Whether a new advertiser is active straight away or waits for your approval is set in [Settings](https://paldock.com/knowledge-base/about-settings/). ###### Adding one manually Two fields are enough: - **Email** - **Nickname** Everything else the advertiser fills in when they first log in, and it appears in the advertiser detail from then on. If the email already belongs to a PalDock account, you are told so, and the email is the only thing you need. The rest of that company’s data already exists and comes with them. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). ###### Self-registration The registration form is yours to define, through the [user structure](https://paldock.com/knowledge-base/user-structure/). It can ask for two kinds of fields. - **Global fields** belong to the PalDock account. Prefer these. For an advertiser who already has an account they are pre-filled, so signing up is close to instant. You cannot edit them, only the advertiser can, and their changes propagate to every workspace they are in. - **Custom fields** belong to your workspace. You define them and you can edit them later in the advertiser detail. See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). ##### Management Assign an admin to the advertiser. That admin sees the results of the advertisers they manage and nobody else’s. See [Admins](https://paldock.com/knowledge-base/admins/). ##### Categorisation Advertisers can be classified by **country**, **language**, **category**, and **tags**. These are filters and grouping dimensions in every report. The advertiser report groups by advertiser, so tags are what let you compare a whole set of them, for example every advertiser in one vertical, without picking them out by hand. ##### What the advertiser sees An advertiser logs into the same interface you do, restricted to their own data. - The offers they own, the results on those offers, and their transactions. - What they pay you is labelled **Costs** on their side. - They see nothing about your affiliates. Which partner produced a lead is yours, not theirs. The access an advertiser has to an offer is set on the offer itself. See [Advertiser](https://paldock.com/knowledge-base/advertiser/). --- ## Admins Admins are your own team. Unlike affiliates and advertisers, they never register themselves. You create the subaccount and invite them. ##### Adding an admin Enter a **name**, an **email**, and optionally a **phone number**, then assign permissions. The account can also be categorised by **country** and **tags**. ##### Permissions Assign one or more: - **Affiliate Manager**: manages affiliate partners only. Can create partners, manage them, and see their performance. - **Offer Manager**: manages advertisers and offers only. Can create offers, manage them, and see their performance. - **Analyst**: views statistics and exports them. No access to partners, offers, or advertisers as entities. - **Viewer**: views entities only. No access to statistics. - **Billing**: invoices and billing documents only, limited to the documents available to the parent account. They combine. Somebody who needs to run partners and read the numbers gets Affiliate Manager and Analyst, not a compromise between the two. ##### Permissions and assignment together A permission says what kind of thing an admin can work with. **Management** says which specific ones. An Affiliate Manager sees the partners assigned to them, not every partner in the workspace. Assignment is done on the partner, in [Affiliates](https://paldock.com/knowledge-base/affiliates/) and [Advertisers](https://paldock.com/knowledge-base/advertisers/). This is what lets two managers work in the same workspace without seeing each other’s accounts, and it is also the thing people forget: an Affiliate Manager with no partners assigned sees nothing, and it looks like broken permissions. ##### What admins do not get - **The account owner’s data.** Nickname, email, password, and billing details belong to the PalDock account and are changed only by its owner, whatever permissions you hold. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). - **Everything in reports.** Individual report functions can be limited by role, from adding a [Highlight](https://paldock.com/knowledge-base/highlights/) to [exporting](https://paldock.com/knowledge-base/export/). An Analyst reads and exports, a Viewer does neither. Access can be suspended or removed at any time. The person keeps their PalDock account and any other workspace they belong to. --- # Reports and Logs ## About Reports and Logs Reports and Logs is where you find out what happened. The difference between the two is the level you are working at. - **Reports aggregate.** A row is a day, an affiliate, an offer, a channel. They answer how many and for how much. - **Logs are one row per event.** A click, a lead, a conversion, a request. They answer why this particular one did what it did. Most questions start in a report and end in a log. ##### The reports - **[Performance](https://paldock.com/knowledge-base/performance-reports/)**: results over time, and the same data grouped by affiliate, advertiser, or offer. This is where you look at profit, costs, revenues, and the per lead and per click metrics. - **[Pingtree](https://paldock.com/knowledge-base/pingtree-report/)**: how leads moved through distribution, per offer and per channel. Pings, verifications, posts, and what each channel paid. - **[Transactions](https://paldock.com/knowledge-base/transactions-report/)**: every transaction as its own row, both sides of it, with the identifiers and the detail behind each one. ##### The logs - **Clicks** and **leads**: what arrived, whether it was accepted, and what happened to it afterwards. - **Conversions**: every conversion PalDock holds and whether it produced a transaction. This is where you go when a conversion exists but no payout came out of it. - **Integration requests**: each run of an integration, node by node, with what was sent and what came back. - **Tracking requests**: every pixel, postback, and Tracking API call, and how each was handled. All of them are described in [Logs](https://paldock.com/knowledge-base/logs/). ##### What every table shares Reports and logs are the same kind of table, so the same tools apply to all of them. - **Period and granularity**: a date picker with the usual presets, and a choice of hours, days, weeks, or months. - **[Highlights](https://paldock.com/knowledge-base/highlights/)**: the key numbers above the table, and the lines in the chart. Rows can be plotted instead. See [Show rows in chart](https://paldock.com/knowledge-base/show-rows-in-chart/). - **[Advanced columns](https://paldock.com/knowledge-base/advanced-columns/)**: which columns are on screen, from a fixed set of groups. - **[Filters](https://paldock.com/knowledge-base/filters/)**: including filtering by columns you are not displaying. - **[Result type filter](https://paldock.com/knowledge-base/result-type-filter/)**: whether pending and rejected transactions are counted. - **[Reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/)**: which of the three dates a transaction is reported on. - **[Export](https://paldock.com/knowledge-base/export/)** and **[Import](https://paldock.com/knowledge-base/import/)**. The last two are worth knowing before you compare numbers with anybody. Two people looking at the same data on a different time basis or a different result filter will get different totals, and both are correct. ##### Who sees what Affiliates and advertisers open the same reports you do, restricted to their own data. Columns that belong to the other side are hidden or relabelled, and an affiliate is never shown which channel bought a lead. See [Transactions report](https://paldock.com/knowledge-base/transactions-report/). Individual report functions can also be limited by role, from adding a Highlight to exporting. ##### Where to start - **Which affiliate is performing best**: performance report, grouped by affiliate. - **Why leads are not selling**: pingtree report, then the lead log. - **Why this lead was rejected**: lead log, read the status, then the detail. - **Why there is no payout for this conversion**: conversion log, then [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). - **Why the advertiser’s postback did nothing**: tracking log, then [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). --- ## Highlights Highlights are the row of key numbers above the table, and they are what the chart plots. They appear on the [Dashboard](https://paldock.com/knowledge-base/dashboard/), in [reports](https://paldock.com/knowledge-base/topics/reports-and-logs/), and in the [logs](https://paldock.com/knowledge-base/logs/). Each Highlight is one metric, summed over whatever you are currently looking at. They follow the date range, the [filters](https://paldock.com/knowledge-base/filters/), the [result type filter](https://paldock.com/knowledge-base/result-type-filter/), and the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/), so the number above the table always matches the table itself. ##### Default metrics A new workspace starts with six: - **Clicks** - **Leads** - **Transactions** - **Costs** - **Revenues** - **Profit** Any performance metric can be used as a Highlight, including the per lead, per click, and per transaction metrics such as EPL, CPC, and ACV. See [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/) for what each one means. ##### How Highlights behave The behaviour differs depending on what the report is built around. ###### Reports over time In reports that show data by date, such as the Performance report, each Highlight is the sum of that metric for the selected period. - Every Highlight has its own colour, and each active one is a line in the chart. - Clicking an active Highlight switches it off. Clicking an inactive one switches it on. - Several Highlights can be active at once. ###### Reports by entity In reports built around entities, such as offers or affiliates, the chart shows **one Highlight at a time**, plotted across the top 10 rows. Showing every Highlight for every row would mean dozens of lines. - The colour belongs to the row, not to the Highlight. - Clicking an inactive Highlight activates it and deactivates the previous one. - The table is sorted by the active Highlight, highest first. - To see several Highlights for a single row, first clear the row selection with the **checkbox icon**. See [Show rows in chart](https://paldock.com/knowledge-base/show-rows-in-chart/). ##### Editing Highlights Highlights are edited from the Dashboard, and the set you choose applies everywhere they appear. - **Add a Highlight**: click **Edit Overview** to enter edit mode. The button then reads **Add**, since you are already editing. - **Remove a Highlight**: hover over it, click the trash icon, and confirm. In edit mode the Highlights are marked in the same edit style used elsewhere in PalDock. There is no way to change what an existing Highlight shows. To swap one metric for another, remove the one you do not want and add the one you do. --- ## Show rows in chart By default the chart plots metrics, one line per active [Highlight](https://paldock.com/knowledge-base/highlights/), each in its own colour. It can also plot the rows of the table instead, so you can compare individual affiliates, offers, or advertisers against each other over time. ##### Selecting rows - Hover over a row and a **checkbox** appears. - Select one or more rows and the **Show in chart** button appears in the table header. - Up to **10 rows** can be plotted at once. In entity based reports the first 10 rows are already selected when the report opens. The **deselect icon** clears them all in one click. ##### What the chart does Once you click Show in chart: - The button turns into **Cancel display** and changes colour. - **With several rows selected**, every Highlight except the main one, Transactions, is switched off. Ten rows across six metrics would be sixty lines, which is why only one metric stays. - **With a single row selected**, the Highlights that were active stay active. The chart simply narrows to that one row. - Active Highlights are shown in **black**, inactive ones in **grey**. - A **legend** appears under the chart listing the selected rows, each with a colour from the same palette the Highlights use. ##### Selected rows and export Selecting rows also changes what you can export. With rows selected, the **Selected** option becomes available in [Export](https://paldock.com/knowledge-base/export/), so you can take out exactly the rows you are looking at rather than the whole table. ##### Time range and granularity The chart follows the period set in the date picker and the granularity chosen next to it: hours, days, weeks, or months. Changing either redraws the chart without affecting which rows are selected. --- ## Advanced columns Every table opens with a core set of columns. Advanced columns are everything else the table can show, from financial detail to the values a partner sent with the lead. Open the picker with the **column icon** in the table header, then switch individual columns on and off. Your selection stays with you, so a table you have set up once opens the same way next time. ##### Column groups Fields are grouped, because the full list is long. The groups always appear in the same order, in the picker and in the table, so a column sits in the same place in every report. - **Performance**: clicks, leads, transactions, revenues, costs, and the metrics derived from them. - **Finance**: payouts, margins, invoice data, and payment statuses. - **Categorization**: tags, categories, countries, languages, and other classification fields. - **Entities**: identifiers and names for affiliates, advertisers, offers, and everything related to them. - **Processing**: the technical side. Source type (link, iframe, API), statuses, processing times, error codes, and similar. - **Data**: the custom fields collected by your forms. ##### Performance metrics The performance columns are laid out in four blocks, separated visually so you can tell at a glance which unit a number is in. ###### Totals The plain counts and amounts for the selected period. - **Clicks**, **Leads**, **Transactions** - **Costs**: what you pay your partners - **Revenues**: what the advertisers pay you - **Profit**: revenues minus costs ###### Per lead - **CR**: conversion rate from lead to transaction - **CPL**: cost per lead - **EPL**: earned per lead - **PPL**: profit per lead ###### Per click - **CR**: conversion rate from click to transaction - **CPC**: cost per click - **EPC**: earned per click - **PPC**: profit per click ###### Per transaction - **ACV**, average conversion value: revenue divided by the number of transactions. How much one conversion is worth. - **APV**, average payout value: payout divided by the number of transactions. How much one conversion costs you. Per lead and per click answer how well traffic converts. Per transaction answers how valuable a single conversion is, which is a different question and often moves in the opposite direction. ##### Columns in logs and the transactions report Row level tables carry columns that make no sense in an aggregated report: - **`affs1` to `affs10`** and **`adv1` to `adv10`**, the custom values passed with the click or the lead - **Device**, **user agent**, and **referrer** - **Value** and **coupon** - **Commission ID**, the commission that created the transaction - **Product** See [Transactions report](https://paldock.com/knowledge-base/transactions-report/) and [Logs](https://paldock.com/knowledge-base/logs/). ##### Hidden columns still work A column does not have to be visible to be useful. - You can **filter** by a column that is switched off. See [Filters](https://paldock.com/knowledge-base/filters/). - You can **export** every available column, whether or not it is on screen. See [Export](https://paldock.com/knowledge-base/export/). This is how you keep a table readable while still working with the full dataset. Filter by country without adding a country column, then export everything when you need the detail. For how each metric is calculated, see [Columns explained](https://paldock.com/knowledge-base/columns-explained/). --- ## Filters Filters narrow down the data shown in tables, reports, and logs. PalDock has two of them. - **Large filter**: a full filter with a field, an operator, and a value. Use it for anything beyond a single column. - **Small filter**: a quick filter applied straight to one column, shown inline in the table. ##### Large filter Click the filter button and a submenu opens with the first empty row ready to fill in. Each row has three parts: - **Field**: what you are filtering. Fields are grouped into categories, because the list is long. - **Operator**: contains, equals, and so on. Which operators are offered depends on the field type. - **Value**: one value or several, again depending on the field type. Every row you add narrows the result further. Rows can be removed one by one, or cleared all at once. ##### Small filter The small filter belongs to a single column and sits in the table itself. It is meant for quick lookups rather than analysis. Some tables offer only this one. In **Offers, List** for example, filtering is done through the small filter on selected columns. ##### You do not have to show a column to filter by it Tables can be filtered by: - **Displayed columns** - **Hidden columns** - **Metrics that are not available as columns at all** This matters most in reports, where you often want to restrict the data without adding another column to an already wide table. Filtering by country, tag, or transaction type works the same whether that column is on screen or not. ##### What you can filter by Beyond the columns of the report itself, the same set of filters is available across reports, logs, and the transactions report: - **Advertiser**, **offer**, **affiliate** - **Transaction type**: prospect, sale, or a custom type - **Origin type**: click or lead - **Source type**: link, iframe, or API - **Category** - **Tags**: on affiliates, offers, and advertisers - **Offer country** and **affiliate country** - **`affs1` to `affs10`** and **`adv1` to `adv10`**, the custom values passed with the click or the lead The custom values are most useful in the logs and in the [Transactions report](https://paldock.com/knowledge-base/transactions-report/), where you are looking at individual rows. In aggregated reports they can produce a very long list of values, since anything the partner sends ends up there. ##### Filters built into each report Every report also carries the filters that make sense for what it groups by: - **Performance report**: advertiser - **Affiliate report**: offer - **Advertiser report**: affiliate, offer - **Offer report**: affiliate, advertiser - **Pingtree report**: no additional filter ##### What partners can filter Affiliates and advertisers use the same reports as you, with two limits. - They see only their own data. A filter never widens that. - **Affiliates cannot filter by channel.** Which channel bought a lead is not something a partner is shown, so that filter is not available to them. ##### Not the same as offer filters Report filters only change what you see. The [filters on an offer](https://paldock.com/knowledge-base/offer-and-pingtree-filters/) decide whether a lead is processed at all. The two look similar and do entirely different things. --- ## Result Type Filter Every transaction carries a result: **pending**, **approved**, or **rejected**. The result type filter decides which of them your reports count. ##### Where it is set - **Per report**, from the filter in the table header. The change applies to the report you are looking at. - **As a workspace default**, in **Workspace Settings**. Every report and the Dashboard open with that selection. The default is **Approved**. The filter is multi-select, so you can combine results. Selecting all three shows everything. ##### What it affects - **Transactional metrics only**: transactions, costs, revenues, profit, and everything derived from them, such as EPL, CPL, ROI and margin. - **Clicks and leads are not affected.** They have no result, so they stay the same whatever you select. This is worth remembering when a report looks inconsistent. A day can show a thousand leads and no revenue simply because every transaction behind them is still pending and the filter is set to approved. ##### Which selection to use - **Approved only**: what you will actually pay out and invoice. The safest basis for financial numbers. - **Approved and pending**: the expected result, including everything the advertiser has not decided yet. Useful for forecasting and for judging fresh traffic, where most transactions are still waiting. - **All three**: for auditing. This is how you see how much an advertiser rejects, and how much of your traffic is being paid for. - **Rejected only**: to investigate rejections, usually alongside the [Transactions report](https://paldock.com/knowledge-base/transactions-report/) or the conversion log. ##### How results are set - The advertiser decides through [tracking](https://paldock.com/knowledge-base/topics/tracking/), by sending the result with the conversion or by updating it later. - [Auto-approve transactions](https://paldock.com/knowledge-base/auto-approve-transactions/) and [Auto-set transaction result](https://paldock.com/knowledge-base/auto-set-transaction-result/) set it on the commission. - You can set it by hand in the Transactions report, or through [manual import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/). Affiliate and advertiser transactions are synchronised, so one result applies to both sides. Approving on one side approves the other. ##### Together with the time basis The filter and the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) answer two different questions, and they are usually used together. - On **approval time**, a rejected transaction sits on the day it was rejected. Filtering to rejected then shows you when decisions were made, not when the traffic came in. - On **approval time**, pending transactions do not appear at all, because they have no decision date yet. Including pending in the filter changes nothing there. --- ## Reporting time basis Every number in a report has to sit on a day. PalDock lets you decide which day that is, because a single journey has three dates on it: the click or lead arrived on one day, the transaction was created on another, and the result was decided on a third. Three options: - **Origin time**: the day the click or lead was created. This is the default. - **Transaction time**: the day the transaction was created. - **Approval time**: the day the transaction result was decided. Switch between them with the **target icon** in the table header. ##### What the choice changes - It moves **transactional metrics only**: transactions, costs, revenues, profit, and everything derived from them. - **Clicks and leads always stay on the day they arrived.** They have no transaction behind them, so there is nothing to move. - Over a long enough period the totals are the same in all three modes. What changes is which day each amount lands on. - Nothing is ever lost. Whichever basis you look at, the payout sits on the partner **balance** and is invoiced from there. The report is a view, not the source of the money. ##### Origin time Everything is reported back to the day the click or lead was created. A sale confirmed today lands on the day its lead arrived, which may be three weeks ago. Use it when: - You are evaluating campaign performance and comparing traffic sources. - You want to know what a given day of traffic was actually worth. - You are making optimisation decisions on recent activity. What to expect: - **Historical days keep changing.** Yesterday looks incomplete, because transactions from yesterday’s leads are still arriving and will be added to it later. - A day is only final once every conversion from it has been decided, which depends on how long your advertisers take. ##### Transaction time Everything is reported on the day the transaction was created, which is the day the conversion arrived and a commission produced a payout from it. Use it when: - You want to see what came in during a period, regardless of when the traffic behind it happened. - You are reconciling against an advertiser who reports the same way. - You are watching conversions arrive day to day. What to expect: - It tells you nothing about when the traffic was generated. A strong day here can come from leads bought months ago. - A transaction created as pending stays on its creation day even after it is later approved or rejected. ##### Approval time Everything is reported on the day the transaction result was decided, whether that decision was approve or reject. Use it when: - You are calculating payouts and issuing invoices. - You are closing a month and need numbers that will not move afterwards. - You need to see when decisions were actually made, for example how long an advertiser is sitting on pending transactions. What to expect: - **Transactions still pending do not appear**, because there is no decision to date them by. They show up on the day they get one. - A rejection lands on the day it was rejected, not the day the sale was reported. Combine this with the [Result Type Filter](https://paldock.com/knowledge-base/result-type-filter/) to separate approved from rejected. - Transactions that are approved automatically are decided at the moment they are created, so for those the approval time and the transaction time are the same. See [Auto-approve transactions](https://paldock.com/knowledge-base/auto-approve-transactions/). ##### Which one to use - **Buying and optimising traffic**: origin time. - **Watching results arrive**: transaction time. - **Paying partners and invoicing advertisers**: approval time. ##### Comparing numbers - Do not compare two periods across two different bases. The same transaction can appear in September on one basis and in October on another. - When your numbers do not match an advertiser or an affiliate, check the basis before checking the data. It is the most common reason two correct reports disagree. - The [Transactions report](https://paldock.com/knowledge-base/transactions-report/) carries all three dates per row, so you can always see where a specific transaction falls on each basis. --- ## Performance reports The performance reports answer the everyday questions: what did I pay, what did I earn, and who or what produced it. They are four views of the same data, and what separates them is what a single row represents. ##### The four reports - **Performance**: one row per time period. This is the report you open to see how the workspace is doing over time. It can be filtered by **advertiser**. - **Affiliate**: one row per affiliate. Filtered by **offer**. - **Advertiser**: one row per advertiser. Filtered by **affiliate** and **offer**. - **Offer**: one row per offer. Filtered by **affiliate** and **advertiser**. The built in filters are the ones that make sense for that grouping. Everything else, from tags to countries to transaction types, is available through the normal [filters](https://paldock.com/knowledge-base/filters/). ##### Drilling down Click an entity name in the first column and the report narrows to that entity and switches to a view by date. From an affiliate row you get that one affiliate’s performance day by day. This is the fastest way to answer why a total changed. The entity report tells you who moved, the drill down tells you when. ##### Secondary grouping Each report has one primary dimension, the thing a row stands for. Secondary grouping adds a second one inside it. - Pick it with the **layer icon** in the table header. - The column header gains the name of the second dimension, as **Affiliate / Offer**. - Each row gets an arrow that expands it into the second dimension. - The dimension you group by is removed from the columns, since it is now the row key. An affiliate report grouped by offer gives you every affiliate, expandable into the offers each of them ran, without leaving the report. ##### What the columns show Every report carries both totals and averages: - **Totals**: clicks, leads, transactions, costs, revenues, profit. - **Per lead** and **per click**: CR, CPL, EPL, PPL, CPC, EPC, PPC. - **Per transaction**: ACV and APV. Which ones are on screen is up to you. See [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/) for the full set, and [Columns explained](https://paldock.com/knowledge-base/columns-explained/) for how each is calculated. ##### Reading the numbers correctly Two settings change what these reports say, and both are worth checking before you draw a conclusion from them. - The [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) decides which day a transaction lands on. - The [result type filter](https://paldock.com/knowledge-base/result-type-filter/) decides whether pending and rejected transactions are counted at all. A report that looks weak on fresh traffic is usually neither of those things being wrong. It is approved only, on origin time, with most transactions still pending. ##### The chart The chart above the table plots the active [Highlights](https://paldock.com/knowledge-base/highlights/). In the entity reports you can plot individual rows instead and compare up to ten of them against each other. See [Show rows in chart](https://paldock.com/knowledge-base/show-rows-in-chart/). --- ## Pingtree reports The pingtree report follows a lead through distribution: how many arrived, how many were offered, who checked them, who verified them, who bought them, and what that was worth. It is the report you open when leads are arriving but not selling. Two levels: - **Pingtree report**: one row per offer. - **Specific pingtree report**: one row per channel inside one offer. Click an offer name to drill into it. Both end with a **SUM row** totalling every column. Channels appear under the names you gave them in the pingtree. See [Pingtree Distribution](https://paldock.com/knowledge-base/distribution/). ##### Grouping The first column is the **Offer**. Below that you can regroup the report: - By channel - By affiliate - By advertiser - By product - By date Secondary grouping works from the same set, so you can look at channels broken down by affiliate, or affiliates broken down by date. The dimension you group by moves out of the columns and becomes the row key. See [Performance reports](https://paldock.com/knowledge-base/performance-reports/) for how the grouping controls work. ##### The columns The columns follow the order of the flow, so you can read a row left to right and see where leads dropped out. ###### Volume - **Total**: leads that entered the pingtree - **Filtered**: leads a channel filter kept out before anything was sent ###### Ping - **Checked**: leads offered to the channel - **Refused check**: the channel said no at the ping - **Error check**: the ping failed technically, for example a timeout or a 5xx ###### Verification - **Verify**: leads sent for verification - **Verified**: leads that passed it - **Refused verify**: verification came back negative - **Error verify**: verification failed technically ###### Post - **Send**: leads posted to the channel - **Accepted**: posts the channel accepted - **Refused send**: posts the channel rejected - **Error send**: the post failed technically ###### Outcome - **Redirected**: customers actually sent on to the advertiser - **Sales**: transactions created - **Rejected**: transactions rejected afterwards ###### Money - **Revenue**: what the channel brought in - **Cost**: what you paid your partners for those leads - **Margin**: revenue minus cost - **EPL**: earned per lead - **CPL**: cost per lead - **PPL**: profit per lead ###### Rates - **Ping rate**: successful pings against pings sent - **Accept rate**: accepted against successful pings - **Sold rate**: sold against successful pings The three rates are what make channels comparable. A channel with a high ping rate and a low sold rate is answering everything and buying nothing, which is a different problem from one that never answers at all. ##### Reading it - **Refused and error are not the same thing.** Refused is the channel deciding no. Error is the request not working. A row full of errors is an integration problem, not a lead quality problem. The [integration log](https://paldock.com/knowledge-base/logs/) has the requests behind it. - **Redirected tells you the lead was alive.** A sold lead that never redirected means the customer left before reaching the advertiser. - **The money columns follow the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) and the [result type filter](https://paldock.com/knowledge-base/result-type-filter/)**, the same as everywhere else. The flow columns do not, since pings and posts have only one date. For how each column is calculated, see [Columns explained](https://paldock.com/knowledge-base/columns-explained/). --- ## Logs Logs are the complete record of what happened in your workspace, and the first place to look when something did not go the way you expected. Where a report tells you how many, a log tells you which one and why. There are five kinds: - **Clicks** - **Leads** - **Conversions** - **Integration requests** - **Tracking requests** They all behave like any other table in PalDock. The same [filters](https://paldock.com/knowledge-base/filters/), [columns](https://paldock.com/knowledge-base/advanced-columns/), and [export](https://paldock.com/knowledge-base/export/) apply, and partners see only their own rows. ##### State Every entry carries a state. - **OK** means it was processed. - **Failed** means it was not, usually because it did not pass validation. A failed entry is normally discarded, unless [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) is enabled, in which case it is kept. State is the coarse answer. The status underneath it says what actually happened. ##### Lead statuses - **Accepted**: the lead was received and is on its way - **Processing**: at least one channel is still working on it. The detail lists the channels and what each is doing, such as waiting, bidding, or verifying - **Sold**: at least one channel bought the lead. The detail lists which ones, for how much, and where the customer was sent - **Not sold**: every channel had its turn and none took it. The detail lists each channel and why, which is where the [reject reasons](https://paldock.com/knowledge-base/reject-reason/) from your integrations show up - **Refused by Validation**: the lead passed the structure but failed an external check, such as a phone or bank account validation. The detail names the field and the check - **Refused by Filters**: the lead was stopped by an offer filter before it reached any channel - **Refused by Pingtree**: the lead went into the pingtree and came out unsold - **Error**: something broke rather than said no. A timeout, a 5xx from an advertiser, or an error inside the pingtree - **Invalid data**: the lead was rejected on arrival. The detail names the field and what was wrong: a required field missing, a value that is not one of the allowed options, or a value that does not match the required format - **Not allowed**: the affiliate is not permitted to send to this offer - **No destination**: there was nowhere to send it. No active channel, no pingtree, or no offer link - **Duplicate**: the advertiser already has this lead ###### Sold and processing together These two can appear at once, and only these two. When one channel has bought the lead while another is still working, the status is **Sold** and the detail shows both. Not sold never appears alongside them, because it is only decided once every channel has finished. ##### Click statuses - **Accepted**: the click was recorded and the visitor was redirected. The detail includes the URL, worth checking when the visitor ended up somewhere unexpected, since a redirect can come from a cap or a rule rather than the offer’s own link - **Invalid data**: a required parameter was missing or malformed - **Bot**: the click was identified as not coming from a person - **Not allowed**: the affiliate is not permitted to send to this offer - **No destination**: no offer link, an inactive offer, or a cap that has been reached - **Refused by Filters**: the click was filtered out ##### The detail The detail column is where the reason lives. For anything involving channels it is a list, one entry per channel, so you can see that Channel A paid, Channel B said the person was a duplicate, and Channel C timed out. That is what makes it worth reading rather than glancing at. The status tells you the outcome, the detail tells you why, and with several channels the answer is different for each one. ##### Conversion logs The conversion log is where you go when a conversion exists but no transaction came out of it. Some conversions succeed and produce a transaction, others do not, for example because they were deduplicated on the advertiser’s external ID. The log tells you which happened. Every step of a conversion’s life is recorded: - created, and created as a child of another conversion - updated - redirected - sent into the pingtree, and what the pingtree answered - what an advertiser answered - every incoming postback, and every [Tracking API](https://paldock.com/knowledge-base/tracking-api/) call sent out Each entry has a severity, so you can tell an ordinary event from a warning and from a genuine error. For the full list of reasons a conversion produced no transaction, see [Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/). When the conversion itself is fine, the cause is on the commission side. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Tracking logs Tracking requests carry a **result** on top of the state, saying whether the request was processed, how it was handled, or why it was refused. The full list of results and what to do about each is on [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). The one you will meet most often is **Unmatched**: the request arrived and was valid, but PalDock could not tie it to any conversion. That almost always means the identifier the advertiser sent is not the one you stored. Start with [Tracking processing](https://paldock.com/knowledge-base/tracking-processing/) and check that `{external_id}` is being stored by your integration. ##### Integration logs Every run of an integration is logged node by node, with the data each node received and returned. This is a different level of detail from the lead log. The lead log tells you the lead was not sold, the integration log tells you which request failed and what came back. See [Connection Creator](https://paldock.com/knowledge-base/topics/connection-creator/). ##### Which log to open - **A lead or a click did not do what you expected**: the lead or click log. Read the status, then the detail. - **A specific request failed against an advertiser**: the integration log. - **A conversion was recorded but there is no payout**: the conversion log. - **A postback or pixel seems to have done nothing**: the tracking log. --- ## Transactions report The transactions report is the row level view of the money. One transaction is one row, and both sides of it, what you pay the affiliate and what the advertiser pays you, live in the same table. Click a row to open the **drawer**, which shows the full detail of that transaction and the conversion behind it. ##### Where transactions come from Transactions are not created here. A [commission](https://paldock.com/knowledge-base/commission-selection/) creates them from a conversion, which is why a conversion with no matching commission produces no row in this report. What you do here: - **Change a result**, individually or in bulk. - **Export** the table. See [Export](https://paldock.com/knowledge-base/export/). - **Correct data in bulk** by importing the conversions the transactions hang from. See [Import](https://paldock.com/knowledge-base/import/) and [Manual Tracking and Transaction Import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/). ##### Results Every transaction carries one of three results: - **Pending** - **Approved** - **Rejected** Workspaces with billing enabled also see **Invoiced** and **Paid**, which describe where the amount is in the payout process rather than whether it was accepted. Affiliate and advertiser transactions are **synchronised**. Approving or rejecting one side applies the same result to the other, so the two can never disagree. See [Commissions](https://paldock.com/knowledge-base/topics/commissions/). ##### Columns Beyond the amounts, the report carries the detail you cannot get from an aggregated report: - **Origin ID, Send ID, Conversion ID, Transaction ID**, the whole chain behind the row. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). - **Transaction type**: prospect, sale, or a custom type - **Origin type**: click or lead, and **source type**: link, iframe, or API - **Commission ID**, the commission that created the row - **Value** and **coupon** - **Product** - **`affs1` to `affs10`** and **`adv1` to `adv10`**, the custom values the partner sent - **Device**, **user agent**, and **referrer** Each row also carries all three dates: when the origin was created, when the transaction was created, and when its result was decided. That is what the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) switches between, and the report is the place to see all three side by side. See [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/) for the full picker and [Columns explained](https://paldock.com/knowledge-base/columns-explained/) for how each is calculated. ##### What partners see Affiliates and advertisers use the same report, restricted to their own rows. ###### Affiliate view - Their own transactions only. - **Costs** is labelled **Revenue**, since from their side it is what they earn. - **Value**, **Revenue**, and **Channel** are hidden. Which channel bought a lead is not something a partner is shown, and no filter or grouping will reveal it. ###### Advertiser view - Their own transactions only. - **Revenue** is labelled **Costs**, since from their side it is what they pay. - **Costs** is hidden. --- ## Import Import lets you create, update, or delete records in bulk from a file instead of one row at a time. The **Import** button appears in the tables that manage those records. ##### Where import is available - **Affiliates and advertisers** - **Commission groups** - **Commissions** - **Conversions** - **Offers** - **Tools**: structures, integrations, designs, feeds - **Settings**: fields, tags, users ##### How it works - Click **Import** in the table. - **Download the template.** It is offered as CSV or XLSX and contains exactly the columns that table accepts. - Fill it in. - Upload it back. - Choose the mode. ##### Import modes - **Create**: adds new rows. IDs are generated by PalDock. - **Update**: changes existing rows. Every row has to carry an ID. - **Delete**: removes records. Every row has to carry an ID. An update or a delete without an ID has nothing to match against, so the row is refused. ##### Importing conversions Conversions are the one import most workspaces use regularly, and they work differently from the rest. **You do not import transactions.** Every transaction belongs to a conversion, so you import the conversion and the [commission](https://paldock.com/knowledge-base/commission-selection/) creates the transaction under it. Rows that match no commission are still imported, they simply produce no payout. An imported row is matched the same way a tracking request is: - **External ID**, together with the advertiser ID. The usual pairing. - **Origin ID** or **Send ID**, when you are pointing at a specific click, lead, or delivery. - **Conversion ID**, for conversions that cannot be addressed any other way. This is the fallback when a row has no external ID and no usable origin. Full detail, including what each row can contain and why a row produced no transaction, is on [Manual Tracking and Transaction Import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/). ##### What to expect - An imported conversion behaves like any other from that point on. It counts towards [deduplication](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) and [recurrence limits](https://paldock.com/knowledge-base/recurrence-type/), and a later postback can still update it. - The result of the import is recorded, so you can see which rows went through and which were refused, and why. --- ## Export Any table in PalDock can be exported for further work in Excel, Google Sheets, or a BI tool. Click the **Export** button in the table header, set the options below, and press **Download**. ##### File format - **CSV**, the default - **XLSX** ##### Delimiter For CSV you choose which character separates the fields: - Comma - Semicolon - Tab Which one you need depends on what will open the file. Excel in a European locale expects the semicolon, most other tools expect the comma. ##### Columns - **All available**: every column the dataset has, including the ones hidden in your current view. - **Only displayed**: the columns currently switched on in the table. Because the export can include hidden columns, you do not have to widen the table just to get a field out of it. See [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/). ##### Rows - **All available**: everything matching your current filters, not just the page you are on. - **Only displayed**: the rows on the current page. - **Only selected**: the rows you ticked in the table. This option appears once at least one row is selected. See [Show rows in chart](https://paldock.com/knowledge-base/show-rows-in-chart/). ##### What ends up in the file - **Your filters are applied.** The export is the table you are looking at, not the raw dataset. That includes the [result type filter](https://paldock.com/knowledge-base/result-type-filter/) and the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/), so an export made on approved transactions contains only approved transactions. - **Amounts carry their currency.** Whenever a column holds an amount, the matching currency is exported next to it, so nothing has to be guessed from the workspace default. - **Partners export what they can see.** An affiliate or an advertiser exporting the same table gets their own rows and their own columns, with the same restrictions that apply on screen. --- ## Columns explained This page explains how the calculated columns in reports are worked out. Columns that hold a plain value, such as names, identifiers, dates, tags, countries, and the fields your own forms collect, are not listed here. For the identifiers behind a row, see [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). For choosing which columns are on screen, see [Advanced columns](https://paldock.com/knowledge-base/advanced-columns/). ##### Rules that apply to every column Four things change what a number says, whatever column it sits in. ###### Currency Reports convert every amount into the **workspace currency** and show one total, because a report with a different currency on every row cannot be read. Transactions, balances, and invoices stay in the **offer currency**, because that is what actually gets paid. See [Currency](https://paldock.com/knowledge-base/currency/). ###### What counts as a click or a lead Three different numbers, three different meanings: - **Gross**: everything that arrived, duplicates included. - **Clicks and leads**: what was counted, after deduplication. - **Unique leads**: how many were the first from that person in the product. See [Origin Deduplication](https://paldock.com/knowledge-base/deduplication/). ###### Time basis and result filter The money and transaction columns follow the [reporting time basis](https://paldock.com/knowledge-base/reporting-time-basis/) and the [result type filter](https://paldock.com/knowledge-base/result-type-filter/). Click and lead columns follow neither, since they have no transaction and no result. This is the usual reason two people reading the same report get two different totals. ###### The partner’s view For an affiliate, **Costs** is labelled **Revenue**, because what you pay is what they earn. For an advertiser, **Revenue** is labelled **Costs**. The number is the same, the label follows who is looking. | Column | Group | How it is calculated | Notes | | --- | --- | --- | --- | | Gross clicks | Counts | Every click that arrived | Includes duplicates and refused clicks | | Clicks | Counts | Accepted clicks after deduplication | The number all click metrics are built on | | Gross leads | Counts | Every lead that arrived | Includes duplicates and refused leads | | Leads | Counts | Accepted leads after deduplication | The number all lead metrics are built on | | Unique leads | Counts | Leads that were the first from that person in the product | Measured on a hash, never on the raw value | | Sends | Counts | Deliveries of a lead to a channel | One lead can have several | | Redirects | Counts | Customers redirected on to an advertiser | Counted once per offer | | Transactions | Counts | Transaction rows created by a commission | One conversion can produce several | | Cost | Money | Sum of affiliate payouts | Shown to an affiliate as Revenue | | Revenue | Money | Sum of advertiser payouts | Shown to an advertiser as Costs | | Profit | Money | revenue – cost | Admin only | | Margin | Money | profit / revenue | Share of revenue you keep | | ROI | Money | profit / cost | Return on what you paid partners | | Value | Money | The order value reported by the advertiser | Not a payout. Empty when the advertiser sends no value | | CR | Per lead | transactions / leads | Conversion rate from lead to transaction | | CPL | Per lead | cost / leads | Cost per lead | | EPL | Per lead | revenue / leads | Earned per lead | | PPL | Per lead | profit / leads | Profit per lead | | CR | Per click | transactions / clicks | Conversion rate from click to transaction | | CPC | Per click | cost / clicks | Cost per click | | EPC | Per click | revenue / clicks | Earned per click | | PPC | Per click | profit / clicks | Profit per click | | ACV | Per transaction | revenue / transactions | Average conversion value. What one conversion is worth | | APV | Per transaction | cost / transactions | Average payout value. What one conversion costs you | | Total | Pingtree | Leads that entered the pingtree | The base for every rate below | | Filtered | Pingtree | Leads a channel filter kept out | Nothing was sent to the channel | | Checked | Pingtree | Leads offered to the channel | The ping | | Refused check | Pingtree | Pings the channel answered with no | A decision, not a failure | | Error check | Pingtree | Pings that failed technically | Timeout, 5xx, or an error in the flow | | Verify | Pingtree | Leads sent for verification | | | Verified | Pingtree | Leads that passed verification | | | Refused verify | Pingtree | Verifications that came back negative | | | Error verify | Pingtree | Verifications that failed technically | | | Send | Pingtree | Leads posted to the channel | The post | | Accepted | Pingtree | Posts the channel accepted | | | Refused send | Pingtree | Posts the channel rejected | | | Error send | Pingtree | Posts that failed technically | | | Sales | Pingtree | Transactions created from accepted leads | | | Rejected | Pingtree | Transactions rejected afterwards | | | Ping rate | Pingtree | successful pings / pings sent | How often the channel answers | | Accept rate | Pingtree | accepted / successful pings | How often it buys what it answered on | | Sold rate | Pingtree | sold / successful pings | How much of what it answered on turned into money | --- # Offers ## About Offers Offers are the core element in PalDock where affiliates send traffic. Each offer represents a campaign or product that can be promoted, tracked, and monetized. Every offer has a **status**: - **Active** – the offer is visible and can be promoted by affiliates. - **Inactive** – the offer is hidden and cannot be used until reactivated. It also has an [access level](https://paldock.com/knowledge-base/offer-access/), which decides which partners can see it and whether they need approval to promote it. Within an offer, you can configure the most important settings, including: - **Tracking links** – the URLs used by affiliates to drive traffic. - **Forms & APIs** – the entry points where leads are submitted, either through an iframe form or directly via API. What they collect is defined by the offer’s [structures](https://paldock.com/knowledge-base/topics/structures/), and an offer can have more than one. - **Payouts & Commissions** – rules for how affiliates are rewarded for approved conversions (clicks, leads, prospects or sales). - **Filters** – conditions that determine whether traffic should be accepted or rejected (e.g., based on data, values, history, or caps). - **Capping** – limits on the number of clicks, leads, prospects or sales an offer will accept. Offers can also include advanced features such as **lead distribution (pingtree)** and **affiliate-specific settings** (e.g., custom payouts or exclusions from certain features). In short, Offers define what affiliates can promote, how the traffic is processed, and under what conditions affiliates are rewarded. --- ## Allowed Delivery method When creating an offer, you can choose how it can be promoted. There are three available methods: - **Link** – redirects the visitor from one website to another. - **Embedded form** – embeds a form on a website to generate leads directly there. - **API** – connects any custom form on the backend to receive leads from it. You can freely decide which methods are available within an **offer** or across the entire **workspace**. ###### Turning a method off for the whole workspace If you disable a method in **Workspace Settings**, all related features are hidden throughout the workspace: - Tabs in offers. - Click and lead metrics and their logs. If both **Form** and **API** are disabled, this also hides: - Pingtrees and their reports. - Structures and their logs. - Integrations and their logs. - Designs. This is about what you see, not about what exists. Nothing is deleted, and turning the method back on brings everything back as it was. ###### Turning a method off for one offer In the **Offer Editor**, only the tabs relevant to the selected methods are displayed. Set this before partners start promoting. A method you disable later leaves links or embed codes already published on partners’ sites, and you need to know what happens to that traffic before you switch it off. --- ## Advertiser Each offer must have a main advertiser assigned. This can later be used in conditions for: - Tracking, especially for postbacks. - Commissions. Additionally, the **Advertiser reports** allow you to view results grouped by advertiser. This is useful when one advertiser has multiple offers, since offer-level reports do not give a complete overview in such cases. ###### Giving advertisers access You can invite **advertisers** into your workspace and give them different levels of access to the offers assigned to them. There are three permission levels: - **View** – the advertiser can log in, see their assigned offers, and view reports and transactions, excluding information about affiliate partners. - **Edit** – in addition to viewing, the advertiser can also edit the offer settings. - **Manage** – full access to the offer, including editing, viewing all related data, and seeing affiliate partners. Ideal if the advertiser handles everything on their side, including approving affiliate requests. This way, you can choose whether advertisers only observe their performance, collaborate on setup, or manage everything themselves. The level applies per offer, so the same advertiser can manage one offer and only watch another. For inviting advertisers and managing their accounts, see [Advertisers](https://paldock.com/knowledge-base/advertisers/). --- ## Offer organization You can categorize and customize your offers by adding the following: - **Logo** – displayed in the offer list and available for affiliates to download. - **System name** – shown in the offer list and throughout the system. - **Display name** *(optional)* – shown on the thank-you page instead of the system name, useful if the system name is not suitable for consumers. - **Country** – assigns the offer to one specific country, or makes it available globally. Used for organizing the offer list. - **Category** – assigns the offer to a single category for easier organization. - **Tags** – allows you to assign multiple tags to an offer for more flexible filtering and grouping. Categories and tags are both managed in Workspace Settings, so the same list is available to every offer. The difference is only in how they are used: one category per offer, any number of tags. --- ## Currency Currently, each offer can have only one assigned currency. This currency is also used for all connected commissions. ###### The offer currency is the real one Everything that happens on the offer happens in its currency. The commission is defined in it, the transaction is created in it, the partner’s balance grows in it, and the invoice is issued in it. Nothing along that path is converted, so the amount a partner sees on the invoice is the amount the commission said. A partner promoting three offers in three currencies has three balances and is invoiced in all three. ###### The workspace currency is for reading, not for paying Reports would be unreadable if every row carried its own currency, so PalDock converts values into the **default currency of the workspace** and shows one total. The default currency is set in Workspace Settings. That conversion exists only so numbers can be added up and compared. It does not change what anyone owes or is owed: - **In reports** you see converted values, so revenue across all offers is one number in one currency. - **In transactions, balances and invoices** you see the offer currency, because that is what gets paid. --- ## Offer description **Offers can be described in detail to help affiliates better understand the product and how to promote it.** You can use a free-text description or two structured tables to present key information more clearly: - **Key Information** – use this section to highlight essential facts about the product, service, or target audience. For example, what the product does, who it is for, pricing specifics, or unique selling points. - **Rules** – clearly define what affiliates are allowed to do and what is prohibited. This helps avoid misunderstandings and ensures that all promotions stay compliant with your brand requirements. You can specify rules around traffic sources, messaging, creatives, and more. Providing clear and complete offer descriptions helps affiliates make better decisions, improves the quality of traffic and leads, and saves time on support and clarification. --- ## Offer Access Defines how visible and available the offer is. It can be set as: - **public **– visible and accessible to all partners - **private **– accessible only if an affiliate requests access and the Admin approves it, or if the Admin adds them manually - **hidden **– not listed in the general catalog and accessible only via direct invitation or link The selected access level determines which partners can see and promote the offer. ###### Changing the level later Partners who already have access keep it. Switching an offer from public to private does not remove anyone, it only stops new partners from taking it without approval. To take access away from someone, remove them from the offer. --- ## Affiliate link Users with access to a specific Offer can view its details together with allowed propagation options (Link, iFrame, API). Affiliate links can carry multiple tracking parameters, all of which are stored in the system and available for reporting and optimization. Each click generates a unique click ID, ensuring that every action can be tracked accurately. The redirection process itself is optimized for speed and reliability, so customers experience minimal delay when clicking a link. #### Link Parameters The most common parameters are: - **`pcid`** – the identifier PalDock assigns to every click. Always present unless you rename it, see below. - **`affcid`** – a custom click identifier provided by the affiliate. - **`affs1`** to **`affs10`** – custom fields where affiliates can pass their own IDs or values for tracking and reporting. - **`destination`** – a URL pointing to another page within the same advertiser domain instead of the default landing page. This allows affiliates to send traffic directly to a specific product or category page, for example an online shop linking users to a chosen product detail. The URL must be URL-encoded, for example `destination=https%3A%2F%2Fwww.example.com%2Fproduct%2F123`. See [Deep link](https://paldock.com/knowledge-base/deep-link/). For the full list, see [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). ###### pcid is the Origin ID `pcid` is the parameter name. The value it carries is the **Origin ID**, which is what identifies a click everywhere else in PalDock: in postbacks, in the Tracking API, in logs and in reports. One value, two names, depending on where you meet it. In a URL it is `pcid`. In everything that talks about it afterwards it is the Origin ID. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). `pcid` is generated automatically, but you can rename it to anything using `?anything={pcid}`. Once `{pcid}` is used in a differently named parameter, the default `pcid` parameter is not added. Only your custom parameter containing the value remains. This is for advertisers whose systems expect the identifier under a name of their own, for example `?clickid={pcid}` or `?subid={pcid}`. ##### Domains and URLs Redirects can run over different domains, giving flexibility in how links are displayed: - **PalDock domain** – default option. (e.g., go.paldk.com/) - **Custom top-level domain** (e.g., www.example.com/). - **Subdomain** (e.g., go.example.com/). - **Folder redirect** (e.g., www.example.com/out/). While this method is slower, it can be useful in email campaigns, allowing the sender domain and the button URL to match, which helps improve deliverability. ##### Redirect Chaining Redirects can sometimes chain together, for example: - A shortened link (e.g., example.com/go/offer) - An affiliate link with parameters (e.g., go.paldk.com/offer=1&affiliate=1) - A tracking link that points to the advertiser (e.g., www.advertiser.com/?source=paldock&id=1) When all of these are handled through PalDock, the system automatically optimizes the path by skipping redundant steps and sending the user directly to the final destination. ##### Remarketing and Scripts Admins can enhance redirects by injecting scripts during the redirect flow via Server-side **Google Tag Manager**. While this may slightly slow down the redirect, it can be well worth it when combined with lead collection. This setup enables advanced remarketing scenarios based on user behavior with the redirects. For example, sending a follow-up email when a customer (known from lead) clicks through a specific link or activating targeted ad campaigns for users who interacted with certain offers. --- ## Deep link PalDock supports deep linking, allowing affiliates to send traffic directly to specific product or landing pages instead of a generic homepage. Each deep link automatically includes the affiliate tracking parameters, ensuring clicks and conversions are correctly attributed. This gives affiliates more flexibility in campaigns, for example linking users straight to a loan application form or a detailed product page while maintaining full tracking and reporting in PalDock. ###### How to build one Add the `destination` parameter to the [affiliate link](https://paldock.com/knowledge-base/affiliate-link/), holding the URL you want the visitor to land on. The value must be URL-encoded, so `https://www.example.com/product/123` becomes `https%3A%2F%2Fwww.example.com%2Fproduct%2F123`. Without encoding, everything after the first `&` in the destination is read as a parameter of the affiliate link instead of part of the destination, and the visitor lands on the wrong page. ###### It has to stay on the advertiser’s domain The destination points to another page within the same advertiser domain, not anywhere on the internet. This is a restriction on purpose: a link that could redirect anywhere would be an open redirect on your domain, and would be abused. If a partner needs to land visitors somewhere the advertiser does not host, that is a different offer, not a deep link. ###### Where it makes sense - **Shops**, where the partner reviews one product and wants the visitor on that product’s page. - **Comparison sites**, where each row leads to the thing that row is about. - **Multi-product advertisers**, where the homepage would make the visitor choose again. Where the advertiser has one landing page and one product, a deep link adds nothing. --- ## Embeddable form Users with access to a specific Offer can view its details together with allowed propagation options (Link, iFrame, API). Embeddable forms allow affiliates to embed a lead form directly on their website. Visitors can fill in the form to convert into a lead, which is then sent to PalDock for processing. The affiliate can copy the embed code from the **Offer Preview** section and customize the form’s style to match their website. Admins define the form structure in **[Form Structures](https://paldock.com/knowledge-base/form-structure/)** and assign them to offers. In the **Design** section, forms can be styled according to tenant needs. ###### Form Parameters The most common parameters used in PalDock are: - **`affcid`** – a custom click identifier provided by the affiliate. - **`affs1`** to **`affs10`** – custom fields where affiliates can pass their own IDs or values for tracking and reporting. - **`affiliateID`** – identifier of the affiliate sending traffic, which can rewrite the original owner of the form. The [AffiliateID rewrite](https://paldock.com/knowledge-base/affiliateid-rewrite/) feature must be enabled. - **`external_redirect_url`** – an alternative URL where the user should be redirected after form submission. The [External Final Page](https://paldock.com/knowledge-base/external-final-page/) feature must be enabled. - **`test`** – marks the lead as a test so it will not be processed as a standard lead. Parameters can be passed either in the URL, which takes precedence, or in the form body. ###### Form Features - **Pre-filling fields** – the form can be prefilled by passing `data_fieldname=value`, where the field name matches a field in the offer’s form structure. The [Pre-filling fields](https://paldock.com/knowledge-base/pre-filling-fields/) feature must be enabled. - **Auto-submit** – the form can be set to submit automatically by adding `system_submit=true`. If some fields are missing, validation triggers an error and the user is asked to complete them. The [Auto submit](https://paldock.com/knowledge-base/auto-submit/) feature must be enabled. ###### The form and the page around it The form runs in an iframe on the partner’s site, which has two consequences worth knowing before you go live: - **The form cannot read the page it sits on.** URL parameters, cookies and referrer belong to the partner’s page, not to the iframe. Anything the form should know has to be passed into the embed URL, or collected afterwards with the [update pixel](https://paldock.com/knowledge-base/update-pixel/). - **Cookies inside the iframe are third-party cookies.** That is why the redirect after submission goes to a page on your own domain rather than staying inside the iframe. See [Pingtree Distribution](https://paldock.com/knowledge-base/distribution/). ###### Tracking in DataLayer The form pushes events to the DataLayer so PalDock or any other tracking scripts can pick them up, for example `started` when the visitor begins filling the form and `lead` when it is submitted. On submission the form also pushes the conversion ID, so tracking scripts can use it to update the lead with additional information from cookies or URL parameters. See [Update pixel](https://paldock.com/knowledge-base/update-pixel/). --- ## API integration Users with access to a specific Offer can view its details together with allowed propagation options (Link, iFrame, API). For each Offer with API propagation enabled, **PalDock automatically generates API documentation for affiliates** (in **Offer preview → API**). The documentation is derived directly from the **[Form Structure](https://paldock.com/knowledge-base/form-structure/)** where input fields are defined. This makes it possible to generate and maintain API specs automatically, so partners can both read and test the integration before development. PalDock uses a single endpoint for all requests and workspaces. The offer and the structure are given as query parameters, so you do not need different endpoints for different tenants or offers. With the Global Fields feature, the payload format stays almost the same across all offers, except when you add custom fields. This setup makes things much easier. Affiliates can run many Offers, even from different workspaces, using just one endpoint. There is no need to handle lots of different URLs and integrations. The PalDock API works the same way everywhere, so integrations are simple and consistent. Thanks to this, integrations are quick and affiliates can start sending their first leads on the very same day they are onboarded. ###### The endpoint ``` `POST https://api.paldock.com/api/{tenant}/conversions/api?o={offer_id}&structure={structure_id}` ``` - **`o`** – the offer the lead belongs to. - **`structure`** – the form structure the payload follows. Both values, along with the affiliate’s API token, are in **Offer preview → API**, where the affiliate can also read the generated documentation and test a request before writing any code. ###### Response codes - **200** – the lead was created. See the response fields below. - **202** – the lead was created and the detailed breakdown is included. See [External Final Page](https://paldock.com/knowledge-base/external-final-page/). - **403** – the API token is not valid. - **404** – no pingtree was found for the given offer and structure. - **406** – the lead was rejected. See [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/). - **422** – the payload or the query parameters did not validate. ###### Process after Lead Submission When a lead is submitted, the response includes `url`. The affiliate’s frontend should send the customer there right away. That URL is the Internal Final Page, `https://portal.paldock.com/{tenant}/processes/{process_id}`. The page waits for the lead to finish processing and then shows the internal screens (verification, thank-you page, final page) or redirects onward, depending on how the Offer is configured. Depending on the Admin configuration, PalDock supports two response modes: **Basic Response** – status and URL only. ``` `{ "process_id": "a1feecc3-dcaf-470b-9b54-f1bdbdeff9dc", "url": "https://portal.paldock.com/tenant/processes/a1feecc3-dcaf-470b-9b54-f1bdbdeff9dc", "origin_id": "1234", "status": "pending" }` ``` **Detailed Response** – full breakdown of how the lead was processed across pingtree channels. See [External Final Page](https://paldock.com/knowledge-base/external-final-page/). ###### Response fields - **`process_id`** – identifies the lead in PalDock. Use it when you ask for the status later, and in the Internal Final Page URL. - **`url`** – where to send the customer next. - **`eid`** and **`origin_id`** – the tracking identifier for this lead. It is the same value the affiliate link carries as `pcid`. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). - **`status`** – `pending`, `approved` or `rejected`. Three older field names are still returned and mean exactly the same as their replacements: `id` for `process_id`, `external_id` for `eid`, and `redirect_url` for `url`. They are kept so existing integrations keep working and will be removed in a future version. Build new integrations on `process_id`, `eid` and `url`. ###### API Parameters The most common parameters used in PalDock are: - **`affcid`** – a custom click identifier provided by the affiliate. - **`affs1`** to **`affs10`** – custom fields where affiliates can pass their own IDs or values for tracking and reporting. - **`external_redirect_url`** – an alternative URL where the user should be sent after submission. Must be URL-encoded. The [External Final Page](https://paldock.com/knowledge-base/external-final-page/) feature must be enabled. - **`external_redirect_url_results`** – whether that page receives the full breakdown or only the basic result. True by default. - **`test`** – marks the lead as a test so it will not be processed as a standard lead. - **`sync`** – holds the response until the lead has been evaluated. The [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) feature must be enabled. See below. - **`status_url`** – a URL PalDock calls when the lead status changes. See below. `external_redirect_url` can carry placeholders that PalDock fills in: `{process_id}`, `{affiliate_id}`, and `{data_}` for any field in the structure. So `https://yourdomain.com/result?pid={process_id}` arrives at your page with the identifier already in it. ###### Tracking Lead Status (Approved or Rejected) When an affiliate sends a lead into PalDock, they may want to know whether it was approved or rejected. PalDock provides three ways to find out. Enable the **[Refuse leads](https://paldock.com/knowledge-base/refuse-leads/)** feature in Offer settings to use any of them. 1. Synchronous response, recommended If the affiliate includes `sync=1`, PalDock holds the response until the offer evaluation is complete, instead of answering straight away with `pending`. - This can take several minutes, depending on the offer logic. - Affiliates must configure a sufficiently long timeout on their side. Although simple, it is the most effective solution. 2. Automatic S2S postback Include `status_url` in the request. PalDock then calls that URL whenever the lead status changes, with the same payload as the standard response. **Request:** ``` `{ "first_name": "John", "last_name": "Doe", "status_url": "https://affiliate.com/postback/lead-status" }` ``` **Postback sent by PalDock:** ``` `{ "process_id": "9e886baa-6804-4dfe-baf9-a065b66d7f87", "status": "approved", "url": "https://portal.paldock.com/tenant/processes/9e886baa-6804-4dfe-baf9-a065b66d7f87" }` ``` No repeated polling, minimal delay, automatic updates. 3. Polling endpoint, not recommended The affiliate can repeatedly ask for the current state using the `process_id` from the initial response. ``` `GET https://api.paldock.com/api/{tenant}/processes/{process_id}` ``` The response has the same shape as the one above. ⚠️ This means calling the endpoint every few seconds until the status changes, which creates unnecessary load on both sides. We do not recommend it in production. ###### API Features - **Data feeds** – responses can include a `feed_id` to match against external data feeds, for example logos, names, or additional attributes. The response may also override certain fields from the data feed for a specific lead. This is useful in cases such as mortgages, where an individual customer might receive a dedicated interest rate. For full details, see [Data feeds](https://paldock.com/knowledge-base/data-feeds/). --- ## Pingtree Distribution A **Pingtree** is a feature that allows you to send a lead to multiple companies at once. Instead of linking one offer to one advertiser, a pingtree lets you group several offers together and decide how they will be distributed. It works on the **Ping** and **Post** basis, where you offer the lead (ping) and if the advertiser wants to buy it, then you send it (post). Think of it as a smart router for your traffic. It decides who gets the customer based on the rules you set. ###### Settings Each line (channel) in a pingtree can have its own settings: - **Channel Name** – the internal name, used in reporting and debugging. We recommend short, structured names such as `channelname_model`, for example `paldock_new_cpl`, so you can filter later by prefix, suffix or middle. - **Visible Name** – the name the customer reads on the Choice Page and the Final Page, and the one returned as `channel_name` in the [External Final Page](https://paldock.com/knowledge-base/external-final-page/) response. Use the company’s real name here, not the internal one. - **Offer** – which offer the channel belongs to. - **Integration** – which [integration](https://paldock.com/knowledge-base/connection-creator-in-integration/) sends the lead to the advertiser. This is what actually does the ping and the post. - **Distribution Type** – which of the four distribution logics applies to the channel. - **Redirect Type** – whether the customer goes straight to the advertiser’s site, stays on a final page, or is only shown there. - **Commission** – the current commission settings for the channel, with the option to create a new one. - **Filter** – conditions that define whether the lead is offered to this channel at all. See [Filters](https://paldock.com/knowledge-base/offer-and-pingtree-filters/). - **Channel Status** – active or inactive. - **Position** – where the channel sits in the pingtree. Drag it to reorder. Position decides evaluation order and, in Choice, the order the customer sees. ###### Distribution Types Pingtree works in four types of distribution logic. These can also be combined: - **Exclusive** – customers are sent to one company at a time, in pingtree order. If the company accepts, the sale ends. If not, the customer continues down the line until someone accepts. - **Non-Exclusive** – the lead is offered to all companies at the same time, regardless of order in the pingtree. Multiple companies can accept it simultaneously. - **Auction** – the customer is offered to all companies (ping), and each returns a price. The customer is sold (post) to the highest bid. - **Choice** – the customer is offered to all companies (ping). The customer sees all successful ping channels on the Choice Page, ordered by their position in the pingtree, and selects which ones they want to apply to (post). Then they see successful post channels on the Final Page where they can complete their application. If a channel has no ping method, it is shown on the Choice Page automatically. Exclusive follows the order you set, so put the channel you expect to earn most at the top. That is usually not the highest raw commission but the highest expected value, which is the commission multiplied by how often that advertiser actually accepts. ###### Redirect Types The **Redirect Type** defines what happens to the customer after the channel succeeds: - **Priority** – immediately redirects to the first successful channel in the pingtree. Since it always takes the first success, order the channels carefully. - **FinalPage** – the channel is displayed on the final page alongside other offers, each with a button leading to the advertiser. - **Visible Only** – the channel is displayed on the final page but with a disabled button, so the customer cannot be redirected to it. - **Hidden** – the channel is not shown on the final page at all. A single channel set to Priority overrides everything else. If it succeeds, the Final Page is never displayed and nothing else is shown, however many other channels also succeeded. ###### Combination of Distribution types All four logics can be combined within a single pingtree. When they overlap, the system follows these rules: - **Exclusive, Choice and Auction channels** are evaluated as grouped blocks, based on their position in the pingtree. Once the system moves to a different type, the previous block is finished. For example, all Auction channels in one block are resolved first, and if no sale occurs, the pingtree continues with the next type. - **Non-Exclusive channels** always run simultaneously, either alongside the first Exclusive channel or alongside the next block. **Examples:** - **Non-Exclusive before Exclusive** – runs in parallel with the first Exclusive. Redirect goes to the first Priority channel or to the Final Page. - **Non-Exclusive before Choice or Auction** – runs in parallel with the whole Choice or Auction block. Redirect again goes to the first Priority channel or to the Final Page. - **Non-Exclusive after Exclusive, Choice or Auction** – only executed if all previous channels in those blocks were unsuccessful. ###### What happens to each channel Every channel in the pingtree ends up with one of four outcomes, and you see them in the [Pingtree report](https://paldock.com/knowledge-base/pingtree-report/): - **ok** – the advertiser accepted the lead. - **fail** – the advertiser did not accept it, or the integration could not complete. - **processing** – the channel is being worked on right now. - **waiting** – the channel has paused and expects something to arrive, typically a webhook from the advertiser. A pingtree that leaves channels in **waiting** for a long time is worth looking at. The customer is not waiting with them, so a late answer arrives after they have gone. ###### Where the Customer is actually Redirected When a lead is created, either through an iframe form or through the API, PalDock immediately generates a **process URL** for that lead: ``` `https://portal.paldock.com/{tenant}/processes/{process_id}` ``` This always exists, whatever the pingtree does. For iframe forms the customer goes there immediately. For API leads it comes back as `url` in the response and the affiliate must send the customer there. See [API integration](https://paldock.com/knowledge-base/api-integration/). The process URL is always opened as a full page on your own domain, never inside the affiliate’s iframe. That is deliberate: a full page means first-party cookies and a clean full-screen experience, while an iframe would depend on third-party cookies and be visually limited. You can replace the PalDock domain with a custom domain of your own. The customer first sees a loader screen, then a sequence of **internal screens** such as verification, thank-you page and final page, depending on how the lead is processed. Admins design these in **Design** and arrange them into funnels in **Funnel**. ###### Where each channel sends the customer That is a different URL, one per channel, and it comes from the advertiser rather than from PalDock. In the channel’s integration, the HTTP node’s response mapping stores the advertiser’s destination in `redirect_url`. That is the address behind the button on the Final Page, and the target of a Priority redirect. A channel that accepts the lead but returns no `redirect_url` has nowhere to send the customer. ###### Visualisation **Example, a Final Page with four successful channels:** - Company4, Redirect **Hidden**, so it is not visible. - Company3, Redirect **Visible Only**. - Company1 and Company2, Redirect **FinalPage**. If any of these channels had **Priority**, the Final Page would not be displayed at all and the customer would be redirected immediately. ###### When a channel is deleted or moved Channels are soft deleted, which means a deleted channel is still visible and still works on Final Pages created before it was removed. This is deliberate. The channel was active at the moment the lead was created, so it was part of that lead’s flow. If capping deactivates a channel, leads that already went through it keep it. - A deleted channel is still visible on older Final Pages. - Its link still works for historical leads. - Deletion or deactivation affects future leads only. There is no full delete, so a channel never disappears from Final Pages that already exist. The same applies to moving a channel. It can be dragged to the end of the pingtree, or from a Non-Exclusive block into a Choice block, and older Final Pages keep the original arrangement, because that was the valid configuration when those leads were created. --- ## Refuse leads Users with access to a specific Offer can view its details together with allowed propagation options (Link, iFrame, API). For iFrame or API submissions, the Admin can configure whether unwanted leads should be rejected. This can be applied to **iFrame only**, **API only**, or to **both**. ###### How leads can be rejected If rejection is enabled in the Offer settings, under **Form** or **API**, a lead may be refused at three points: - **Validation** – the lead must pass the rules on the fields it carries, whether that is a field type, a regex or a validation scenario. See [Field validation](https://paldock.com/knowledge-base/field-validation/). - **Offer Filters** – the lead must satisfy the Offer’s filter conditions to be eligible for processing. See [Filters](https://paldock.com/knowledge-base/offer-and-pingtree-filters/). - **Lead Processing Result** – the lead must be accepted by at least one channel in the [pingtree](https://paldock.com/knowledge-base/distribution/). If no channel accepts it, it is refused. You can choose which of these a lead must pass before being approved: - **Everything** – validation, filters, and pingtree processing. - **Validation** – field and external validation only. - **Filters** – the Offer filters only. - **Pingtree** – acceptance by at least one channel only. You can include or exclude specific affiliates from this feature. Alternatively, duplicate the offer just for them if you want a different setup. ###### Lead Approval and Rejection **If lead refusal is disabled**, the status is always *approved*. Every lead is marked approved, even if it would not have met the criteria. **If lead refusal is enabled:** - The status starts as *pending* until processing is complete. - If the lead meets the criteria, the status changes to *approved*. - If it does not, the status changes to *rejected*. Sample API response: ``` `{ "process_id": "9e886baa-6804-4dfe-baf9-a065b66d7f87", "status": "pending", "url": "https://portal.paldock.com/tenant/processes/9e886baa-6804-4dfe-baf9-a065b66d7f87" }` ``` ###### Choosing what to check The four options are not four levels of strictness, they are four different questions. - **Validation** asks whether the data is usable. Turning it on rejects leads the partner could have fixed, which is fair to tell them about. - **Filters** asks whether you want this lead at all. A duplicate or a lead outside your target group is rejected here even though the data is perfect. - **Pingtree** asks whether anyone bought it. This is the strictest in practice, because it makes the partner’s payment depend on your advertisers, not only on the quality of their traffic. Partners notice the difference. A lead rejected because the phone number was wrong is a conversation about data quality. A lead rejected because every advertiser was capped that afternoon is a conversation about your inventory. ###### Tracking Lead Status Affiliates may want to track the status of each lead, whether it was approved or rejected. PalDock provides several ways to obtain this information. For full details, see [API integration](https://paldock.com/knowledge-base/api-integration/). ###### Verification Rejection has to be immediate, because the customer is waiting to be redirected. Verification is not immediate, because it waits for the customer to do something, for example confirm a code or sign a document. The two cannot both be true at once, so verification resolves it this way: - The lead is set to *approved* when it reaches the verification step, and the customer is redirected. - It stays *approved* whatever happens next. A customer who never completes the verification does not turn the lead into *rejected*, and neither does a channel that later declines it. So *approved* means the lead passed the checks you set and was handed over. It does not mean it was sold. Whether the customer finished, and whether the advertiser eventually paid, is a separate question answered by the [transaction](https://paldock.com/knowledge-base/topics/commissions/) rather than by the lead status. An offer with verification will normally show more approved leads than transactions, and that gap is the verification drop-off, not a fault. Tell partners this before they build their reporting on the lead status. A partner who counts approved leads as sales will be wrong by exactly that gap. --- ## Process refused leads This feature is connected to the [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) setting. By default, a refused lead stops where it was refused. It gets `fail` in the **State** column, nothing further happens to it, and it does not appear in standard reports. You find it in the [Leads log](https://paldock.com/knowledge-base/logs/). **Process refused leads** sends it through the rest of the flow anyway. The lead stays refused towards the affiliate, so there is no payout and it does not count in reports, but it can still be distributed and the customer can still be redirected. You can include or exclude specific affiliates from this feature. ###### Why this exists A refused lead is a lead you decided not to buy from the partner. That is not the same as a lead nobody wants. Two examples: - **Embedded form lead.** A lead passes form validation but is rejected by filters, for example as a duplicate. It does not increase the accepted lead count in reports, but you can still redirect the customer, for instance to finish an application they left unfinished. - **API lead.** A lead fails validation and the partner cannot correct the data. It remains rejected, with no payout and no effect on reports, but it can still go into the pingtree and be sold. In both cases the partner sent you something you are not paying for, and it would otherwise be thrown away. The partner usually has nowhere else to send it either. ###### It only applies to leads refused before the pingtree The refusal criterion decides whether there is anything left to do: - **Validation** and **Filters** refuse the lead before it reaches the pingtree, so there is still a whole flow to run. This is where the feature is useful. - **Pingtree** means the lead already went through the pingtree and nobody took it. There is nothing further to try. See [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) for setting the criteria. ###### What it does not change - The lead stays refused. - It is not counted as a valid lead in reports. - The affiliate is not paid for it. So refused describes what you owe the partner, not what happens to the customer. --- ## External Final Page The External Final Page feature lets partners, or you yourself, replace the internal PalDock Final Page with their own page. Use it to keep control of the branding, to show PalDock results alongside your own offers, or to build the results into a comparison site. It works with both API and iFrame submissions. Admins decide whether to enable it for API only, iFrame only, or both. ###### The flow, once Whatever else you configure, this part never changes: - A lead is created. The response contains `process_id` and `url`. - **`url` always points to the Internal Final Page**, `https://portal.paldock.com/{tenant}/processes/{process_id}`. It never points at your page. - The customer goes there. From an iframe this happens automatically, from the API your frontend does it. - The Internal Final Page redirects onward to your external page. - Your page reads the result and renders it. Everything below only changes **when** step 4 happens and **how** you get the data in step 5. ###### What you configure Six settings on the offer, plus three parameters on the request. They are independent, and confusing them is the usual reason an integration behaves unexpectedly. On the offer: - **External Final Page** – turns the feature on, and for which submission methods. - **Default External Final Page** – the URL every partner is sent to, unless excluded. - **Skip internal loader and redirect immediately** – whether PalDock’s loader waits for the pingtree or hands over straight away. - **Include results in redirect** – whether the results travel in your page’s URL as query parameters. - **Partners with Override & Detailed Response** – which partners may send their own URL and receive the full channel breakdown. - **Partners without Default External Final Page** – which partners are excluded from the default URL. On the request: - **`sync=1`** – the API call waits for the pingtree instead of answering immediately. - **`external_redirect_url`** – your own URL, instead of the default. Requires the override permission. - **`external_redirect_url_results`** – full channel detail, or just status and type. True by default. Four of the six offer settings are outside the partner’s control, so a partner cannot fix a missing loader or missing query parameters on their own side. ###### Two setups that work **A. Let PalDock wait.** *Skip internal loader* disabled, *Include results in redirect* enabled. The Internal Final Page holds the customer on its loader until the pingtree finishes, then redirects to your page with the result already in the query string. - Your page is static and renders once from the URL. - No polling and no JavaScript needed for the data. - The customer looks at a PalDock loader for as long as the pingtree takes. **B. Show your own loader.** *Skip internal loader* enabled. The Internal Final Page redirects to your page straight away, while the pingtree is still running. Your page shows its own loader and polls until the result is ready. - The customer is in your branding the whole time. - You have to handle the waiting state as well as the finished one. Pick A when your page is rendered server-side. Pick B when the wait is long enough that the customer should spend it looking at your site. ###### Getting the data **From the query string.** With *Include results in redirect* enabled, fields are flattened onto your URL and encoded. Nested names keep their shape, so `items[0].channel_id` arrives as `items_0_channel_id`. **By polling the Process API.** ``` `GET https://api.paldock.com/api/{tenant}/processes/{process_id}` ``` Watch the status code, because two different objects come back from this endpoint: - **202** is the External Final Page response, the same object the redirect flattens. Here `url` holds the resolved external page URL. - **200** is the internal Final Page response, which has a different shape and is not what you want. Polling works in both setups, so even in setup A you can poll if *Include results in redirect* is off. ###### Knowing when it is finished `is_finished` is the only reliable signal. - **false**, the pingtree is still running. What you read is a snapshot and channels can still change. - **true**, it has reached a terminal state and nothing more will change. Do not infer this from the statuses. A channel sitting in `waiting` may still be answered. If you send `sync=1`, the API call itself waits for the pingtree, so the response may already carry the finished result and there is nothing to poll for. `url` still points at the Internal Final Page even then. See [API integration](https://paldock.com/knowledge-base/api-integration/). ###### How much detail you get `external_redirect_url_results` controls the shape of `items`. True by default. - **true**, the full array: `channel_id`, `channel_name`, `status`, `type`, `redirect_url`, `send_id` and any `exs_1` to `exs_5`. - **false**, a basic array with only `status` and `type`. Use false when your page only needs to know how it went, true whenever you render the channels themselves. ###### Who gets what Two lists, and each does something different. **Partners with Override & Detailed Response** grants two things at once: - The partner may send `external_redirect_url` and be sent to their own page instead of the default. - The partner receives the detailed response with the full channel breakdown. There is no way to grant one without the other. A partner who should see the channel results has to be trusted with the redirect URL as well. **Partners without Default External Final Page** is the opposite: a partner on this list is not sent to the default page at all. The two combine into three outcomes: - **On neither list.** The partner goes to the Default External Final Page and gets the standard response. - **On the override list.** The partner can send their own URL and receives the detailed response. Without sending one, they still get the default page. - **On the exclusion list only.** The partner has no external page at all and stays on the internal Final Page. Both lists fail quietly. A partner sending `external_redirect_url` without the override permission lands on the default page and nothing tells them why, so check the list first when a partner reports the wrong page. ###### The URL and its placeholders Both the default URL and `external_redirect_url` support placeholders that PalDock fills in: - `{process_id}` – the process ID of this lead. - `{owner_id}` – the affiliate the lead is attributed to. - `{data_}` – any submitted field value, for example `{data_first_name}`. `external_redirect_url` must be fully URL-encoded, including `&`, `?`, `{` and `}` inside the value, so the whole thing is read as one parameter rather than several. ###### What comes back About the lead: - **`process_id`** – identifies the lead. Use it for polling. - **`url`** – the Internal Final Page when the lead is created, the resolved external page when polling. - **`origin_id`** – the Origin ID of the click or lead this came from. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). - **`status`** – the overall state, using the same values as the channels below. - **`is_finished`** – whether processing is complete. - **`items_total`** – how many channels the lead reached. - **`successful_items`** – how many accepted it. About each channel, in `items`: - **`channel_id`** – the channel’s ID, shown in the pingtree editor. Match on this. - **`channel_name`** – the channel’s visible name. - **`status`** – `ok`, `fail`, `processing` or `waiting`. See [Pingtree Distribution](https://paldock.com/knowledge-base/distribution/). - **`type`** – the channel’s distribution type: `exclusive`, `non_exclusive`, `auction` or `choice`. - **`redirect_url`** – where the advertiser wants the customer sent. Empty when the channel did not accept. - **`send_id`** – the Send ID for this one channel. One lead going to five channels produces five Send IDs. Use it to match a later postback to the right channel. - **`exs_1`** to **`exs_5`** – extra values from the advertiser’s response, where the integration maps them. `origin_id` and `send_id` are not the same thing. The Origin ID belongs to the lead and there is one of them. A Send ID belongs to one attempt at one channel, and there is one per item. ###### Building the page Match on **`channel_id`**. It is stable and visible in the pingtree editor. Names change, IDs do not. The pattern that works on a comparison site is to prepare a hidden row for every channel in advance, each tagged with its channel ID, and reveal the rows that came back with `ok`. Your page then needs no logic beyond showing and hiding, and it already has the logos, names and copy, because it is the same data your comparison used before the form. Alongside the successful channels you can show offers outside the pingtree and display ads. The page is yours. ###### When there is nothing to compare If the result has a single item and that channel is Exclusive or uses Priority redirect, there is nothing to compare. Send the customer straight to `redirect_url`. The redirect flow already does this and skips the external page in that case. Decide separately what to show when **no** channel accepted. That page will be seen, and an honest message is better than an empty comparison table. --- ## Data feeds A data feed holds product information such as names, logos, prices or availability, and PalDock can match a lead against it. API responses include a `feed_id`, which tells you which feed the data for that lead comes from. The response can also override individual values from the feed for one specific lead. This matters where the offer is standardised but the price is not, for example a mortgage where an individual customer is quoted their own interest rate. The [External Final Page](https://paldock.com/knowledge-base/external-final-page/) uses the same feed to match products, which is the most common reason to set one up. --- ## Affiliate ID rewrite You can override the affiliate a lead is attributed to by passing the parameter `owner_id`: - in the URL of the affiliate link, or - in the URL of the page containing the embedded form. Example: `www.example.com?owner_id=12345` ###### Affiliate link use case This is useful when you want to place an offer link on your final landing page and attribute the resulting conversion to the affiliate delivering the traffic. ###### Embedded form use case This is useful when you generate traffic on your own website but want to attribute certain traffic sources to a separate affiliate account. By appending `owner_id` to the URL, those leads are tracked under the specified affiliate. ###### It decides who gets paid The affiliate on a lead is the affiliate you pay for it, so this parameter moves money rather than just labelling a report. Use it where you control the page it sits on, and remember that anyone who can edit that URL can change the attribution. --- ## Pre-filling fields Forms can be pre-filled by passing parameters in the query string of the page containing the form, in the format `data_fieldname=value`. The field name is the system name of a field in the offer’s [form structure](https://paldock.com/knowledge-base/form-structure/). This reduces friction and improves the user experience by displaying information you already know, such as name, email or phone number. The **Pre-filling fields** feature must be enabled in the Offer settings. ###### The `data_` prefix The prefix is what separates field values from everything else in the URL. `affcid` is a tracking parameter, `data_email` is a value going into a field called `email`. Global fields carry their own prefix instead, so a global email is `g_email` rather than `data_g_email`. See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). ###### Building the URL from a lead you already have If you want to generate a pre-filled URL for each lead, create a hidden form field that combines all the values in this format: ``` `data_fieldname1=value1&data_fieldname2=value2&data_fieldname3=value3` ``` Store it without the domain, so you can append it to any destination URL, for example in an email campaign. Remember that values have to be URL-encoded. An address with a space or an email with a plus sign breaks the query string otherwise, and the fields after it are lost. ###### Anyone with the link can read it A pre-filled URL carries personal data in plain sight. It sits in browser history, in server logs on the receiving side, and in the referrer header of anything the page loads. That is usually acceptable for a link you send to that person by email, and not acceptable for a link that could be shared or indexed. Do not pre-fill anything you would not put on a postcard. You might also want to check out the [Auto submit](https://paldock.com/knowledge-base/auto-submit/) feature, which automatically submits the pre-filled form without requiring user action. --- ## Auto submit The form can be set to submit automatically by adding the parameter system_submit=true. However, if some fields are missing, the form’s validation will trigger an error and the user will be asked to complete the missing fields. (Feature Auto submit must be enabled). **Use case** Auto Submit is especially useful when monetizing a lead generation database. Since you already have all the required user information, the lead can be sent directly into the pingtree (e.g., after the user clicks a button in an email). **Optional confirmation step** If you want to add an additional confirmation from the user, you can create a dedicated internal page that the user visits before the form is submitted automatically. You might also want to check out the **[Pre-filling fields](https://paldock.com/knowledge-base/pre-filling-fields/)** feature, which automatically prefills the form with values to have it ready to be auto-submitted. --- ## Offer and Pingtree Filters ⚠️ Do not confuse these with report filters. The functionality looks similar, but these filters decide whether a lead is processed at all. Filters can be exported using the code icon (``) or imported via the **+ Filter from template** button. They work on logical **OR** and **AND** conditions and can be grouped or nested for complex setups. ###### Two places, one tool The same filter builder is used in two places, and the only difference is what a failed condition blocks: - **On the offer.** The lead does not enter the offer at all. Nothing further happens to it, and with [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) enabled it is refused. - **On a channel in the pingtree.** The lead enters the offer as normal, but this one channel is skipped. Every other channel still gets its chance. See [Pingtree Distribution](https://paldock.com/knowledge-base/distribution/). Use the offer level for what you do not want at all, and the channel level for what one advertiser will not take. A lead outside your target country belongs on the offer. A lead below one advertiser’s minimum income belongs on their channel. ###### Available Filters - **Offer if lead is not from an Affiliate partner** - **Offer if lead is from an Affiliate partner** - **Offer if a field value meets a condition** Any field from the form can be compared using operators: equals, starts with, ends with, contains, does not equal, greater than, or less than a specific value. - **Offer if the ratio between values meets a condition** Calculates the percentage ratio between two numeric values from the form. - **Offer based on history** Do not use the offer if the lead has already been: sent to this offer - rejected by this offer - accepted by this offer - rejected for a specific reason, which requires selecting both the period and the reason - **Offer if an external server request returns 200** The request runs while the customer is waiting, so keep the timeout short. A service that takes three seconds to answer costs three seconds on every lead, whatever it replies. - **Offer if the lead creation time is not within a restricted period** Restrict by specific days of the week, for example Sunday, or by time ranges. - **Limit the number of sold clicks or leads** Set a maximum number per period. This is how capping is configured. See [Lead and Click Capping](https://paldock.com/knowledge-base/lead-and-click-capping/). ###### Filter before you ping Every ping costs time the customer spends on a loading screen. A filter that removes a channel which would have rejected the lead anyway saves that time and saves the request. So the rule of thumb is to filter on anything you already know, such as country, product or the partner, and ping only for what you cannot know without asking. --- ## Lead and Click Capping Capping is configured directly in [Filters](https://paldock.com/knowledge-base/offer-and-pingtree-filters/). You define a maximum number of events, whether that is a click, a lead, a sale or a custom conversion type, within a time window such as per hour or per day. Once the limit is reached, the system stops offering or processing further events according to the filter rules. This gives you controlled delivery and keeps you inside agreed volumes, on links, embedded forms and the API alike. ###### Two places to cap Capping follows the same split as every other filter: - **On the offer**, the cap closes the whole offer for that period. Nothing more comes in. - **On a channel in the pingtree**, the cap closes one advertiser and the lead continues to the others. An advertiser who only wants 200 leads a day belongs on their channel. A budget you cannot exceed belongs on the offer. ###### What the customer sees A capped offer still receives the traffic, it just stops accepting it. Decide what happens to those visitors before the cap is reached, rather than after. - With a pingtree, a capped channel is skipped and another one takes the lead, so the customer notices nothing. - With a capped offer and no alternative, the lead is refused. See [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/) and [Process refused leads](https://paldock.com/knowledge-base/process-refused-leads/). ###### Which event to count Capping clicks and capping leads solve different problems. Clicks limit how much traffic arrives, leads limit how much you buy, and sales limit what you owe the advertiser. Capping sales is the closest to a real budget, but it is also the loosest control, because clicks and leads keep costing you effort until a sale finally hits the cap. --- # Commissions ## About commissions **⚠️ A commission is simply a rule that defines when and how a transaction should be created from a conversion.** Conversions are performance metrics on their own. They carry no money. A commission is the rule that turns a conversion into a **transaction** with a payout and a result. Every commission exists twice: once for your workspace, meaning what you receive from the advertiser, and once for your partners, meaning what you pay them. The two are linked, so both transactions are always created together. ##### What you can control - **When a transaction is created**, using conditions such as offer, advertiser, conversion type, source, and channel. - **How much it is worth**, as a fixed value, a percentage, or a calculation using system fields and values from tracking. - **What type of transaction it is**, and what result it gets when it is created. - **How duplicates and repeats are handled**, using recurrence limits and deduplication on the advertiser’s external ID. - **Who it applies to**, using commission groups. ##### Start here - [Commission conditions to create Transactions](https://paldock.com/knowledge-base/commission-conditions-to-create-transactions/) sets which conversions a commission applies to. - [Commission amount](https://paldock.com/knowledge-base/commission-amount/) sets what the transaction is worth. - [Commission status](https://paldock.com/knowledge-base/commission-status/) controls whether a commission applies at all. ##### When several commissions apply - [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/) explains which commission runs and how many of them run. - [Multiple Commissions for the Same Conversion Type](https://paldock.com/knowledge-base/multiple-commissions-for-the-same-conversion-type/) - [Commission order](https://paldock.com/knowledge-base/commission-order/) - [Commission ID](https://paldock.com/knowledge-base/commission-id/) lets the advertiser name the exact commission in a tracking request. ##### Controlling the transaction - [Transaction type](https://paldock.com/knowledge-base/transaction-type/) - [Auto-approve transactions](https://paldock.com/knowledge-base/auto-approve-transactions/) - [Auto-set transaction result](https://paldock.com/knowledge-base/auto-set-transaction-result/) ##### Avoiding duplicates - [Recurrence type](https://paldock.com/knowledge-base/recurrence-type/) limits how many times one commission can be applied to the same conversion. - [Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) keeps one transaction per external ID. ##### Organizing and presenting - [Commission group](https://paldock.com/knowledge-base/commission-group/) targets commissions at selected affiliates. An affiliate can belong to only one group. - [Commission schedule](https://paldock.com/knowledge-base/commission-schedule/) changes amounts over time. - [Display amount](https://paldock.com/knowledge-base/display-amount/) shows a clean label instead of a formula. - [Commission detail](https://paldock.com/knowledge-base/commission-detail/) adds a short note to the commission table. PalDock calculates reporting metrics such as ROI from the difference between your amount and the partner payout. See [Performance reports](https://paldock.com/knowledge-base/performance-reports/). --- ## How the commission is selected When a conversion is recorded, PalDock looks for commissions that apply to it. This page explains which ones are found, how many of them run, and why a matching commission still might not create a transaction. ##### Step 1: matching the conditions A commission matches when every one of its conditions either matches the conversion or is left empty. Empty means “any”. - **Offer** - **Advertiser** on workspace commissions, or the affiliate on partner commissions - **Conversion type** - **Source**, read from the original click or lead, not from the conversion that arrived last - **Channel**, when the offer uses [Pingtree](https://paldock.com/knowledge-base/distribution/) - **Commission group** of the affiliate who owns the conversion ##### Step 2: how many commissions run PalDock collects every commission that matches. What happens next depends on where the conversion came from. - **Clicks and leads created by PalDock** from an affiliate link, iFrame, or API: all matching commissions run. One lead can create several transactions at once, one per commission. - **Everything else**, meaning pixel, postback, Tracking API, and manual import: only one commission runs, even if several match. If the tracking request contains a **Commission ID**, that commission is used. It still has to match the conditions above, so a Commission ID that belongs to a different offer or conversion type will not be applied and no transaction is created. See [Multiple Commissions for the Same Conversion Type](https://paldock.com/knowledge-base/multiple-commissions-for-the-same-conversion-type/). ##### Step 3: which one runs when only one can When only one commission can run and several match, a filled condition beats an empty one. PalDock compares them in this order: - Offer - Channel - Conversion type - Source - Commission group A commission limited to one offer therefore beats a commission that applies to all offers. If two commissions are still equal, [commission order](https://paldock.com/knowledge-base/commission-order/) decides and the first one in the list wins. The commission is chosen before its status is checked. If the winning commission turns out to be inactive, no transaction is created and the next commission in the list is not used instead. ##### Step 4: the partner commission Once the workspace commission is chosen, PalDock picks the partner commission below it. The affiliate gets the commission set for their [commission group](https://paldock.com/knowledge-base/commission-group/). If that group has no commission set, the one without a group is used. This happens for every workspace commission that runs, so the workspace transaction and the matching partner transaction are always created together. ##### Step 5: the final checks A commission that was chosen still creates nothing if any of the following is true. - The commission is **inactive**. - The conversion falls **outside the commission’s active period**. The dates are compared against the time the conversion happened, not the time the tracking arrived. A postback that comes in late still uses the commission that was valid when the conversion was created. - The **[recurrence](https://paldock.com/knowledge-base/recurrence-type/) limit** for that commission has already been reached. - The conversion is **not valid**, for example because it was rejected or marked as a duplicate. - The conversion was **created by a commission itself**. Conversions that PalDock creates to hold a transaction of a different [transaction type](https://paldock.com/knowledge-base/transaction-type/) never trigger commissions again. ##### Why no transaction was created Check these in order in the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/). - No commission matches the conversion type. - A Commission ID was sent that does not match the rest of the conditions. - The commission that won is inactive or outside its active period. - The recurrence limit was reached. - The conversion was deduplicated on the [advertiser’s external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/). --- ## Commission status A commission can have two statuses: **active** or **inactive**. In practice, in the commission table: - **Active** commissions have any amount or calculation filled. - **Inactive **commissions have a dedicated commission type marked with 🚫. If you want to create a transaction from a commission without any payout – for example, just to record a microconversion, you can enter “**0”** in the amount. You can also make a commission active only for the workspace or only for affiliates (and vice versa). Just be aware that if you pay affiliates for leads but only receive a payout from the advertiser for sales, you risk a loss if those leads do not convert well enough. --- ## Commission conditions to create Transactions **⚠️ A commission is simply a rule that defines when and how a transaction should be created from a conversion. The settings below are only available for workspace commissions from advertisers, because partner commissions reflect those values.** Conversions on their own are only performance metrics without a payout. Conditions decide which conversions a commission applies to, and therefore when a transaction is created. Conversions reach PalDock in two ways: - **Created by PalDock**, such as clicks, leads, and sends. - **Received through tracking**, such as prospects and sales, via [pixel](https://paldock.com/knowledge-base/tracking-pixel/), [postback](https://paldock.com/knowledge-base/tracking-s2s-postback/), [Tracking API](https://paldock.com/knowledge-base/tracking-api/), or [manual import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/). ##### Available conditions - **Offer**: choose one or more offers (required). - **Advertiser**: choose one or more advertisers. - **Conversion type**: the [type of conversion](https://paldock.com/knowledge-base/conversion-type/) that triggers the commission, such as click, lead, send, prospect, sale, or a custom type. - **Source**: all sources, or only one, such as affiliate link, iFrame, or API. - **Channel**: when the offer uses [Pingtree](https://paldock.com/knowledge-base/distribution/), you can name each channel and reference that name here. ##### How the conditions are evaluated - A commission applies when **every** condition either matches the conversion or is **left empty**. Empty means “any”. - **Source is read from the original click or lead**, not from the conversion that arrived last. A sale sent by postback still counts as coming from the affiliate link that started it. - When several commissions match the same conversion, see [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Conditions are not the only check Even a matching commission creates no transaction if: - It is **inactive** or outside its active period. See [Commission status](https://paldock.com/knowledge-base/commission-status/). - Its **[recurrence](https://paldock.com/knowledge-base/recurrence-type/) limit** has been reached. - The conversion was **[deduplicated](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)** on the advertiser’s external ID. ##### What the transaction looks like The conditions decide **whether** a transaction is created. What it looks like is set elsewhere: - [Commission amount](https://paldock.com/knowledge-base/commission-amount/) sets the value. - [Transaction type](https://paldock.com/knowledge-base/transaction-type/) sets the type. Without it, a prospect conversion creates a prospect transaction and everything else creates a sale. See [Prospect + Sale vs Pending Sale](https://paldock.com/knowledge-base/prospect-sale-vs-pending-sale/). --- ## Multiple Commissions for the Same Conversion Type If multiple commissions exist for the same **conversion type**, the behavior depends on how the transaction is created. When a transaction is created automatically by the system based on commission rules, all commissions whose conditions are met will be triggered. When a transaction is created through [Tracking Pixel](https://paldock.com/knowledge-base/tracking-pixel/) or [Postback](https://paldock.com/knowledge-base/tracking-s2s-postback/), only one commission is selected, using this priority: - Based on received **Commission ID** - The first commission (based on [order](https://paldock.com/knowledge-base/commission-order/)) matching the provided **Type**, if **Commission ID** is not provided - The first commission (based on [order](https://paldock.com/knowledge-base/commission-order/)) in the list based on weight order, if neither **Commission ID** nor **Type** is provided The default commission is always the first one in the commission list, but you can reorder commissions at any time using drag and drop. --- ## Auto-approve transactions ###### ⚠️ This setting is only available for workspace commissions from advertisers, because partner commissions reflect those values. If you are certain that you want specific transactions to be approved automatically, you can enable this in the **advertiser commission detail** under the **Settings** section “Auto-approve transactions.” When enabled, any **pending **transactions that meet the commission’s conditions will be automatically marked as **Approved** without manual review. Affiliates will see these commissions as approved, and depending on your payout settings, they may become eligible for immediate payout. In the commission list, those commissions will be marked with a ⚡ next to the transaction type. You might also want to check out the **[Auto-set result](https://paldock.com/knowledge-base/auto-set-transaction-result/)** feature, which allows you to automatically change a transaction’s result after a specified period of time. --- ## Auto-set transaction result ###### ⚠️ This setting is only available for workspace commissions from advertisers, because partner commissions reflect those values. **Auto-set result** automatically changes the **pending **transaction status after a specified period of time. You need to define: - **Time period** – how long to wait before changing the status. - **Final status** – the status to apply after that period (Approved, Rejected, or Pending). This feature is useful if you want to automate status updates after a review window or validation process, for example, approving transactions after 30 days if no rejection has been received. Auto-set result is applied only to pending transactions. You might also want to check out the **[Auto-approve](https://paldock.com/knowledge-base/auto-approve-transactions/)** feature, which approves transactions immediately without waiting for the set time. --- ## Transaction type ###### ⚠️ This setting is only available for workspace commissions from advertisers, because partner commissions reflect those values. **Transaction type** sets what kind of transaction a commission creates. You can choose any [conversion type](https://paldock.com/knowledge-base/conversion-type/), including custom ones. By default, the system has the following transaction types. | Conversion type | PalDock | Tracking | Transaction Type | | --- | --- | --- | --- | | Sale | ❌ | ✅ | ✅ | | Prospect | ❌ | ✅ | ✅ | | Send | ✅ | ❌ | ❌ | | Lead | ✅ | ❌ | ❌ | | Click | ✅ | ❌ | ❌ | | View | ✅ | ❌ | ❌ | ##### The default If you leave the setting empty, the transaction gets the type of the conversion that triggered the commission. A sale conversion creates a sale transaction, a prospect conversion creates a prospect transaction. ##### Why you would change it - To pay for a different event than the one that arrived, for example paying a prospect commission on an incoming sale. - To split payouts inside one offer, with one commission for prospects and another for sales. - To group several custom conversion types into one transaction type for reporting. Combine it with the other [commission conditions](https://paldock.com/knowledge-base/commission-conditions-to-create-transactions/) so each commission catches the right conversions. See [Prospect + Sale vs Pending Sale](https://paldock.com/knowledge-base/prospect-sale-vs-pending-sale/) for a worked example. ##### When the type differs from the conversion A transaction always belongs to a conversion of the same type. When the transaction type is different from the type of the conversion that triggered the commission, PalDock creates the missing conversion for it. - PalDock first looks for an existing conversion of that type **under the same original conversion**. If it finds one, the transaction is added there. - If there is none, PalDock **creates a new conversion** of that type and puts the transaction under it. - The new conversion **inherits the data** of the conversion it came from, so the affiliate, offer, and IDs stay the same. - The new conversion **never triggers commissions again**, so this cannot loop. - One commission creates **one transaction** on that conversion. If the same commission runs again for the same conversion, no second transaction is added. ##### What you see as a result: - Reports count the new conversion under its own type. - An extra conversion appears in the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/), and the original conversion carries no transaction. - The workspace transaction and the partner transaction both sit on this new conversion. --- ## Recurrence type ###### ⚠️ This setting is only available for workspace commissions from advertisers, because partner commissions reflect those values. **Recurrence** limits how many transactions one commission can create for the same customer journey. It protects you when an advertiser sends the same conversion more than once, whether by mistake or because they cannot deduplicate on their side. ##### The options - **Once**: the commission creates one transaction and then stops. This is the default for new commissions. - **Limited**: you set the maximum yourself. - **Unlimited**: the commission is applied every time a matching conversion arrives. Existing commissions keep the setting they already have, so older ones may still be unlimited. Check them if you see repeated transactions. ##### Allowing more than one transaction **⚠️ When multiple conversions are enabled for a single commission, update postbacks will not work unless an External ID or Conversion ID is provided, as the system cannot determine which conversion should be updated.** With **Once**, there is only ever one conversion to update, so an update postback can find it on its own. With **Limited** or **Unlimited** there can be several, and PalDock has no way to tell which one the advertiser means. - Agree with the advertiser that every request carries an **[external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)**, unique per order, before you move away from Once. - A **conversion ID** works too, when the advertiser stores the one PalDock returned. - Without either, updates are ignored and results stay Pending, even though new conversions keep being created normally. ##### What counts towards the limit PalDock counts the transactions already created by **this one commission**, and only those that match all of the following: - They sit on a conversion that belongs to the **same original click or lead**, anywhere in that chain. - The conversion has the **same type**, so sales and prospects are counted separately. - The conversion has the **same advertiser**. - The conversion has the **same [external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)**. Conversions that arrived without an external ID are counted together as one group. Transactions on invalid or rejected conversions are not counted. ##### When the limit applies - The limit is checked on conversions that follow an original click or lead. The **original click or lead itself is never limited**, because there is nothing before it to repeat. - When the limit is reached, the commission is **no longer offered for that conversion**. If another commission matches, that one is used instead. Nothing is created if none does. ##### What this means in practice - The limit is **per commission**, not per offer. Two commissions on the same offer each keep their own count, so one order can still create one prospect transaction and one sale transaction. - Because the external ID is part of the match, an advertiser who sends a **different external ID for each order** can create several transactions from one click even with Once. That is usually what you want for repeat purchases. - An advertiser who sends **no external ID at all** gets one transaction per commission with Once, because everything falls into the same group. - An advertiser who sends **no external ID at all** gets one transaction per commission with Once, because everything falls into the same group. Raising the limit for such an advertiser is rarely useful, because their updates cannot be matched either. ##### Recurrence or deduplication Both prevent duplicate transactions, but they act at different points. - **Recurrence** limits how many transactions a commission may create. It works even when the advertiser sends no external ID. - **[Deduplication based on the advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)** refuses the duplicate conversion itself, before any commission runs. Use both. Deduplication keeps your conversion data clean, recurrence is the safety net when the external ID is missing. --- ## Deduplication based on advertiser's ID When the same conversion reaches PalDock more than once, whether by mistake or because you run several tracking methods at once, deduplication keeps a single record of it. It works through the **`external_id`** parameter, the advertiser’s own ID for the order. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). ##### How the duplicate is recognised A conversion is treated as a duplicate when a valid conversion already exists with the same: - **External ID** - **Advertiser** - **Conversion type** If three requests arrive with the same order ID, one conversion is recorded and one transaction is created, not three. Because the conversion type is part of the match, a **prospect and a sale with the same external ID both pass**. They are different events on the same order. ##### What happens to the duplicate - The request is accepted and **logged**, so nothing is silently lost. - The conversion is marked as a duplicate and **stays invalid**, so no commission runs on it and no transaction is created. - You can see it in the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/) with the duplicate status. ##### When the Commission ID changes the outcome If the request carries a **[Commission ID](https://paldock.com/knowledge-base/commission-id/)**, deduplication is judged per commission instead of per conversion. - **Without a Commission ID**: the second conversion is refused whichever commission would apply. - **With a Commission ID**: the second conversion is refused only if that commission already created a transaction for this external ID. Another commission can still be applied. ##### Why you should always send external id Even when you are not worried about duplicates, the external ID is what lets PalDock recognise an order later. - **Update requests** need it. Without an external ID or a conversion ID, PalDock cannot tell which conversion the advertiser means, so results are never updated. See [Recurrence type](https://paldock.com/knowledge-base/recurrence-type/). - **[Recurrence](https://paldock.com/knowledge-base/recurrence-type/) limits** are counted per external ID, so repeat orders from the same customer are paid correctly. - If the first request arrives without one and a later request for the same conversion brings it, PalDock **saves it onto the conversion**. An external ID that is already stored is never overwritten. There is no way to add it afterwards by hand, so ask the advertiser to send it from the start. ##### Deduplication or recurrence - **Deduplication** refuses the duplicate conversion itself, before any commission runs. It needs the external ID. - **[Recurrence](https://paldock.com/knowledge-base/recurrence-type/)** limits how many transactions one commission may create. It works even with no external ID. --- ## Commission amount The commission amount defines what a transaction is worth, both for you and for your partners. There are three types. ##### 1. Fixed amount A value that is always used, no matter what arrives in tracking. Only digits and the `.` separator are allowed. Use it for standard CPA and CPL deals. ##### 2. Percentage - On **workspace commissions**, the percentage is taken from the **value received in tracking**. Value 100 with a 10% commission gives 10. - On **partner commissions**, the percentage is taken from the **workspace commission amount**. A workspace commission of 10 with a partner commission of 50% pays the partner 5. What the affiliate sees follows from that: - If the workspace amount is **fixed**, the affiliate sees the calculated amount, not the percentage. You receive €100, the partner share is 20%, the affiliate sees €20. - If the workspace amount is a **percentage**, the affiliate sees a percentage of the value. You receive 5% of the value, the partner share is 50%, the affiliate sees 2.5% of the value. ##### 3. Calculation A formula that PalDock evaluates when the transaction is created. Use it when the amount depends on what the advertiser sends. ###### Fields you can use - **`{value}`**: the order value from tracking. Example: `0.05 * {value}` - **`{commission}`**: the payout amount itself, when the advertiser tells you what they will pay rather than what the order was worth. Example: `{commission}` - **`{parent}`**: on partner commissions, the workspace commission amount. Example: `0.5 * {parent}` - **`{field_name}`**: any field from the lead’s structure, written exactly as the field is named. Example: `0.02 * {loan_amount}` Formulas accept lowercase letters, digits, `.`, brackets, and `+ - * /`. ###### Combining several fields The formula is not limited to one field. You can use everything the advertiser sends in the same calculation, so the payout reflects what you are actually being paid on. Typical deductions from the reported amount: - **Tax or VAT** - **Bonuses and free credit**, which the advertiser does not pay you for - **Discounts and vouchers** - **Chargebacks, fees, or any other cost** you carry Example for a gaming advertiser paying 25% of net revenue: `0.25 * ({value} - {bonus} - {tax} - {fees})` Two things to keep in mind: - **Every field in the formula has to arrive** with the conversion. One missing field makes the whole amount 0, not just that part of it. Agree the full list with the advertiser before you go live. - Wrap deductions in **brackets**. `0.25 * {value} - {bonus}` subtracts the bonus after the percentage, which is almost never what you want. ###### Setting the amount in a scenario `{commission}` is filled in two ways. - The **advertiser sends it** in the tracking request, in the `commission` parameter. - **You set it yourself** in the tracking scenario, which is the more common case. In the scenario, use a **Set node** to write the amount into `{commission}`, and put **conditions on the connections** leading to each node to decide which amount applies. Then set the commission formula to `{commission}` and every lead gets the amount its own path produced. This is how you pay tiered amounts without creating a separate commission for each tier. Example: a consumer loan advertiser pays more for larger loans. One scenario, three Set nodes: - Connection condition `{required_amount}` is less than 5000, Set node writes `40` into `{commission}` - Connection condition `{required_amount}` is 5000 or more and less than 8000, Set node writes `70` - Connection condition `{required_amount}` is 8000 or more, Set node writes `90` The commission formula stays `{commission}` for all of them. Change the tiers by editing the scenario, not the commissions. The same pattern works with any field the advertiser sends, such as product category, country, or plan name. Use `{value}` when the deciding field is the order value itself. See [Connection Creator in Tracking](https://paldock.com/knowledge-base/connection-creator-in-tracking/). ##### When a value is missing If the request does not contain a field your formula needs, the amount is **0** and a transaction is still created. Watch for this when you switch an advertiser to a percentage or a formula. - Agree with the advertiser which fields are sent with every conversion, and that they are sent even when they are zero. - Check the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/) after the first live conversions. - Keep a fixed amount as the fallback commission if the advertiser is unreliable. ##### Keeping it readable - Use **[Display amount](https://paldock.com/knowledge-base/display-amount/)** to show a clean label such as “5%” instead of the formula. - Use **[Commission detail](https://paldock.com/knowledge-base/commission-detail/)** for a short note in the commission table. A common case: you receive 10% of the value from the advertiser and want to pay partners 5% of the same value, not 5% of your commission. Set the partner formula to `0.05 * {value}` and the Display amount to “5%”. ##### Where to set it - In the **Commissions** section, to edit several offers at once. - In **Offer settings**, when you only need one offer. PalDock calculates reporting metrics such as ROI from the difference between your amount and the partner payout. See also [Commission groups](https://paldock.com/knowledge-base/commission-group/) for paying different affiliates differently. --- ## Display amount **Display amount** lets you replace a complex commission formula with a clear, user-friendly label. This makes it easier for you and your partners to quickly understand the payout logic without exposing the underlying calculation. For example, if your formula is 0.05 * {value} to pay partners 5% of the value, you can simply set the Display amount to **“5%”** instead of showing the full formula. If the Display amount does not provide enough context, you might also want to check out the **[Commission Detail](https://paldock.com/knowledge-base/commission-detail/)** feature, which allows you to add a short descriptive note that appears in the commission table. --- ## Commission detail If you have multiple commissions for the same goal, or are using a calculation that you want to clarify, you can use the **Commission detail** field to add a short descriptive note. This helps distinguish similar commissions or make the purpose of a formula clear at a glance. The Commission detail appears directly in the commission table, so it should be concise, ideally just a few words. You might also want to check out the **[Display amount](https://paldock.com/knowledge-base/display-amount/)** feature, which can simplify how the payout value itself is shown. --- ## Commission schedule You can set up multiple Commission schedules, where you define: - **From** date - **To** date - Which commission group it applies to - Amount - Amount type (fix, %, calculation) - Display amount These changes cannot overlap. Once one period ends and no subsequent change is set, the default amount will be used. --- ## Commission group Commission groups let you pay different affiliates different amounts for the same offer, without creating a separate offer or a separate commission for each of them. Groups apply to **partner commissions only**. A workspace commission always exists once per offer and conversion type, because there is nothing to segment on your own side. - A group can contain **one or many affiliates**. - An affiliate can belong to **only one group**. - Affiliates you have not put anywhere belong to the **Default group**. ##### What gets created You never create partner commissions by hand. PalDock keeps them in sync for you. - When you create a **workspace commission**, PalDock creates one partner commission under it **for the Default group and for every other group**. - When you create a **new group**, PalDock creates a partner commission for that group under **every existing workspace commission**. - All of them start as **inactive**, so nothing is paid out before you set the amounts. ##### What the partner commissions inherit Each partner commission copies the conditions of the workspace commission above it: offer, conversion type, source, channel, active period, transaction type, and auto-approve. Those fields cannot be changed on the partner commission, and any later change to the workspace commission is passed down automatically. What you set per group is the part that differs: - The **[amount](https://paldock.com/knowledge-base/commission-amount/)** - The **[display amount](https://paldock.com/knowledge-base/display-amount/)** and **[detail](https://paldock.com/knowledge-base/commission-detail/)** - Whether the commission is **active** for that group ##### Which one applies An affiliate is always paid by the commission for **their own group**. There is no fallback. - If the commission for that group is **inactive**, the affiliate gets no transaction. The commission of another group is never used instead. - Activate the commission in **every group** that should be earning on the offer, not just in the Default group. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Working with groups - Start with the **Default group** and add more only when you actually need to pay someone differently. - **Deleting a group** moves its affiliates to the Default group, so they are paid by the Default group commission from then on. - Moving an affiliate between groups changes what they earn on **future** transactions. Transactions already created keep their amount. - Groups are **workspace-wide**, not per offer, so one group covers all your offers at once. --- ## Commission order Order sets the sequence in which commissions are applied to a conversion. ##### What decides which commissions run - Every commission whose **[conditions](https://paldock.com/knowledge-base/commission-conditions-to-create-transactions/) match** the conversion is applied. One conversion can therefore create several transactions. - A **[Commission ID](https://paldock.com/knowledge-base/commission-id/)** in the tracking request narrows this to that one commission. Order does not decide **whether** a commission is used, only **when** it is processed. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### How the list is ordered - Order is kept **separately for each offer and conversion type**, so moving a commission up affects that offer and that type only. - **Workspace commissions and partner commissions have their own order.** Partner commissions are chosen by [commission group](https://paldock.com/knowledge-base/commission-group/), not by position. - A **new commission is added to the end** of its list. ##### Why the sequence matters Transactions are created in this order, so it is also the order you see them in and the order in which they are sent out through the [Tracking API](https://paldock.com/knowledge-base/tracking-api/). Put the commission you consider the main one for that conversion type first. See [Multiple Commissions for the Same Conversion Type](https://paldock.com/knowledge-base/multiple-commissions-for-the-same-conversion-type/). --- ## Commission ID Every commission in PalDock has its own ID. Sending it with a tracking request tells PalDock exactly which commission to apply, instead of letting the system choose. ##### When you need it - You have **more than one commission for the same conversion type** and the advertiser has to say which one applies. - You pay **different amounts for different products or plans** inside one offer. - You want the **[recurrence](https://paldock.com/knowledge-base/recurrence-type/) limit** counted separately for each commission, because the limit is counted per commission. - You want **[deduplication on the external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)** to allow a second conversion for a different commission. See below. If you only have one commission per conversion type, you do not need it. ##### How to send it - Parameter name: **`commission_id`** - Format: the commission UUID, for example `9e321d3b-3690-4100-821d-86476cc4c2fb` - Supported in the **[tracking pixel](https://paldock.com/knowledge-base/tracking-pixel/)**, **[S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/)**, and the **[Tracking API](https://paldock.com/knowledge-base/tracking-api/)** - Not used in the **[affiliate postback](https://paldock.com/knowledge-base/affiliate-postback/)**, which sends results out rather than in - Alternatively, send **`commission_code`** with the commission’s own text code instead of the ID The parameter is optional in every request. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/) for the full list. ##### Commission code Instead of the Commission ID, you can send a **commission code**: a short text label you set on the commission yourself. - It works as an alias, so `commission_code=premium-plan` does the same as sending that commission’s ID. - It is easier to read and easier for advertisers to implement than a UUID. - It does not change any behaviour. Everything on this page applies to the code the same way it applies to the ID: the conditions are still checked, deduplication still works per commission, and the recurrence limit is still counted per commission. - If you send both, the **Commission ID wins**. Use the code when the advertiser maps their own product names to your commissions. Use the ID when the request is generated by a system that can store it. ##### What happens when you do not send it When neither the Commission ID nor the commission code is sent, PalDock falls back to [commission order](https://paldock.com/knowledge-base/commission-order/): - If **`type`** is sent, the first commission in the list for that conversion type is used. - If neither is sent, the first commission in the list is used. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### What happens when the ID does not fit The Commission ID does not skip the commission conditions, it only narrows the choice to one commission. That commission still has to match the conversion. - If the commission belongs to a **different offer, conversion type, channel, or source**, it will not be applied and **no transaction is created**. - The request itself is still accepted and the conversion is still recorded. Check the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/) to see that no transaction was created. Always send an ID that belongs to the same offer as the conversion. ##### Effect on deduplication The Commission ID changes how [deduplication on the advertiser’s external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) works. - **Without a Commission ID:** a second conversion with the same external ID is refused, no matter which commission would apply. - **With a Commission ID:** a second conversion with the same external ID is refused only if that specific commission already created a transaction for it. A different commission can still be applied. This is useful when one order should create two transactions, for example a prospect and a sale, and both arrive with the same external ID. --- # Tracking ## About Tracking Tracking is how conversions get into PalDock. It records clicks, leads, prospects, sales, and any custom type you define, and it decides what data those records carry. Turning them into payouts is a separate step, handled by [commissions](https://paldock.com/knowledge-base/topics/commissions/). ##### The tracking methods - **[Pixel](https://paldock.com/knowledge-base/tracking-pixel/)**: browser based, fired on the advertiser’s confirmation page. Easy to deploy, but depends on cookies and can be blocked. - **[S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/)**: server to server, sent by the advertiser’s system. Reliable and cookie free. - **[Tracking API](https://paldock.com/knowledge-base/tracking-api/)**: PalDock asks the advertiser’s system about a conversion, or forwards results out to an affiliate. - **[Manual import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/)**: upload conversions yourself when no automated method is available. Most setups combine at least two, typically a pixel and a postback, so a blocked pixel does not cost you the conversion. When the advertiser sends their own [external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/), PalDock recognises the repeats and keeps a single conversion. ##### Start here - **[Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/)**: which identifier to send and when. Read this before you brief an advertiser. - **[Tracking processing](https://paldock.com/knowledge-base/tracking-processing/)**: what happens to a request after it arrives. - **[Conversion type](https://paldock.com/knowledge-base/conversion-type/)**: which types exist, which channel can create which type, and how to add your own. - **[Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/)**: the full parameter reference. A step by step setup guide for a specific offer is in the **Offer editor, Tracking tab**. ##### Setting up each method - [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/) - [Update pixel](https://paldock.com/knowledge-base/update-pixel/), for adding URL and cookie data to a conversion that already exists - [Tracking S2S Postback](https://paldock.com/knowledge-base/tracking-s2s-postback/) - [Tracking API](https://paldock.com/knowledge-base/tracking-api/) - [Manual Tracking and Transaction Import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/) ##### Attribution and duplicates - **[Tracking by vouchers](https://paldock.com/knowledge-base/tracking-by-vouchers/)**: a discount code assigns the conversion to the affiliate who owns the code. - **[Click deduplication](https://paldock.com/knowledge-base/deduplication/)**: repeated clicks from the same visitor count once. - **[Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)**: the same order reported twice counts once. ##### Sending results out - **[Affiliate postback](https://paldock.com/knowledge-base/affiliate-postback/)**: affiliates forward their own results into their systems. ##### When something does not work - **[Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/)**: see the raw requests and the conversions they produced. - **[Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/)**: what each outcome and status means, and what to do about it. A conversion that is recorded correctly still does not have to produce a payout. That depends on the commission. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). --- ## Conversion IDs explained PalDock gives every step of the journey its own ID. Sending the right one is what decides whether a tracking request creates a new record, updates the right one, or fails to match anything. ##### The objects - **Origins** are clicks and leads. Every journey starts with one. - **Sends** are the individual deliveries of a lead to a channel in a [Pingtree](https://paldock.com/knowledge-base/distribution/). One lead can have many sends. - **Conversions** are sales and prospects, whether they arrived through tracking or were created by a commission. - **Transactions** are conversions that a commission applied to, so they carry a payout amount and a result. ##### The IDs - **Origin ID**: the click or the lead. Created by PalDock at the very start and passed to the advertiser. This is the ID you use to attribute anything back to the affiliate. - **Send ID**: one delivery of a lead to one channel. Use it when you need to talk about a specific channel in a Pingtree, not about the lead as a whole. - **Conversion ID**: one sale or prospect. Created when the conversion is recorded. - **Transaction ID**: one transaction. A conversion can have several if several commissions apply. - **External ID**: the advertiser’s own ID for the order. You do not create it, the advertiser sends it. See [Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/). - **Affiliate CID**: the affiliate’s own ID for the conversion, sent as `affcid`. PalDock stores it and sends it back so the affiliate can match records on their side. - **Process ID**: not an object ID. It identifies one asynchronous API call while it is being processed. ##### Which one to send **Creating a conversion**, by pixel, postback, or Tracking API: - Send the **Origin ID**, or the **Advertiser ID together with the External ID**. Either pair is enough to attribute the conversion. - Sending both is the safest option and we recommend it. **Updating a conversion:** - Send the **External ID with the Advertiser ID**. - Or send the **Conversion ID** when you have it. It is unambiguous. - The Origin ID alone is not enough once more than one conversion exists under the same origin, because PalDock cannot tell which of them you mean. ##### Pingtree: why the Origin ID is not enough In a [Pingtree](https://paldock.com/knowledge-base/distribution/), one lead is sent to several channels. Every one of those sends carries the **same Origin ID**, because they all come from the same lead. That has a direct consequence for tracking: - The advertiser receives the Origin ID and sends it back with the conversion. - PalDock cannot tell **which send** that conversion belongs to, because several sends share that ID. - Two advertisers in the same Pingtree can therefore report against the same Origin ID. What to use instead: - **Advertiser ID together with External ID** is the reliable pairing in a Pingtree. The advertiser is unique, their own order ID is unique on their side, and the combination points at exactly one conversion. - **Send ID** identifies one delivery to one channel. Pass it to the advertiser in the integration and ask for it back if you want the conversion tied to that exact send. - **Origin ID on its own** is fine for a single-channel offer, and unreliable as soon as a Pingtree is involved. If you run Pingtrees, agree with every advertiser that they always return their External ID. Without it you cannot separate their conversions from another channel’s. ##### Where you find them - **Click and lead log**: Origin ID - **Integration log**: Origin ID, Send ID - **Conversion log**: Origin ID, Send ID, Conversion ID, Transaction ID - **Transaction report**: Origin ID, Send ID, Conversion ID, Transaction ID In API responses: - A completed call returns the **Origin ID** and, for a Pingtree, the **Send ID**. - A call that is still running returns the **Process ID**, and the object IDs once it finishes. - Pixel and postback responses return the **Conversion ID** and the **Origin ID**. Store what you get. The Origin ID is the one you will need most often later. --- ## Tracking processing This page explains what happens to a tracking request between the moment it arrives and the moment a transaction exists. Every method goes through the same steps: [pixel](https://paldock.com/knowledge-base/tracking-pixel/), [S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/), [Tracking API](https://paldock.com/knowledge-base/tracking-api/), and [manual import](https://paldock.com/knowledge-base/manual-tracking-and-transaction-import/). ##### Step 1: the request is checked - The request must pass **validation**. A request without an identifier, or with an unknown conversion type, is refused. - If it was sent to a postback that has **conditions** on source, offer, advertiser, affiliate, or type, it must match them. If it does not, it is logged as Filtered and ignored. - The **conversion type must be allowed on that channel**. Not every type can be created through every method. See [Conversion type](https://paldock.com/knowledge-base/conversion-type/). ##### Step 2: PalDock finds the conversion Every request has to be tied to something that already exists. PalDock looks in this order: - **Advertiser ID together with External ID** - **Origin ID** - If neither matches an existing conversion, the original click or lead is used as the parent When several conversions already exist under one origin, PalDock narrows the search to the child conversions of the type in the request. If exactly one matches, that one is used. If several match, the request is logged as Unmatched and nothing happens, because PalDock cannot guess which conversion was meant. - **Affiliate links** cannot use the External ID, because it does not exist yet at click time. Use the Origin ID. - **iFrame and API** integrations can use either. - Sending **both** is the safest option and works in every case. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### Step 3: create or update The **`action`** parameter decides what happens next. - **`action=create`** records a new conversion. The **`type`** parameter is required. - **`action=update`** changes an existing one, for example to set the result or the value. - If `action` is missing, the request is treated as a create. Two cases worth knowing: - An **update that finds no conversion** returns an error and changes nothing. - An **update that lands on a click, lead, or send** while carrying a different `type` creates a conversion of that type instead. This is how a sale reported against a click ends up as a sale conversion rather than overwriting the click. - Send **`create=false`** when you want an update to fail rather than create anything. ##### Step 4: duplicates are filtered out If the advertiser sends an **External ID**, PalDock checks whether a valid conversion with the same External ID, advertiser, and type already exists. If it does, the new one is stored as a duplicate and no transaction is created. See [Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/). If the first request arrived without an External ID and a later one brings it, PalDock **saves it onto the conversion**. A value that is already stored is never overwritten. Clicks, leads, and sends never carry an External ID. ##### Step 5: commissions run Only now does PalDock look at commissions. A recorded conversion does **not** mean a payout. - The conversion must match a commission’s conditions. - The commission must be active, within its period, and within its recurrence limit. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Combining tracking methods Most setups run more than one method, because each fails in different circumstances. - **Pixel**: fires immediately on the confirmation page, and is lost when the browser blocks it. - **S2S postback**: arrives when the advertiser processes the order, from seconds to days later. Some send daily batches. - **Tracking API**: PalDock asks the advertiser, so the timing is yours to control. - **Manual import**: the fallback when nothing else is available. The same conversion can therefore arrive up to four times. The External ID is what keeps it as one conversion, so agree on it with every advertiser before going live. ##### What to send - **Always**: an identifier, either the Origin ID or the Advertiser ID with the External ID. - **When creating**: `type`. - **When more than one commission exists** for that type: [Commission ID](https://paldock.com/knowledge-base/commission-id/). - **When you have it**: `result`, `value`, and the External ID, every time, even on updates. The full list is on [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). --- ## Conversion type Conversion types are the events PalDock records. Every conversion has exactly one type, and it decides which commissions can apply and which pixel is used. See table below to know which types are created by which event. | Conversion type | PalDock | Tracking | Transaction Type | | --- | --- | --- | --- | | Sale | ❌ | ✅ | ✅ | | Prospect | ❌ | ✅ | ✅ | | Send | ✅ | ❌ | ❌ | | Lead | ✅ | ❌ | ❌ | | Click | ✅ | ❌ | ❌ | | View | ✅ | ❌ | ❌ | - **Click**: a visitor followed an affiliate link. - **Lead**: a form was submitted through an iFrame or the API. - **Send**: one delivery of a lead to one channel in a [Pingtree](https://paldock.com/knowledge-base/distribution/). A lead can have several. - **View**: an impression. - **Prospect** and **Sale**: reported by the advertiser through tracking. Types created by PalDock cannot be created by a tracking request. Tracking can only update them, and an update that carries a different type creates a conversion of that type instead. See [Tracking processing](https://paldock.com/knowledge-base/tracking-processing/). ##### Custom conversion types When the six built-in types are not enough, create your own in **Workspace Settings, Tracking, Conversion types and pixels**. Custom types behave like sale and prospect: they are reported through tracking and can be paid on. Each type, custom ones included, comes with its **own tracking pixel**, in an advertiser version and an affiliate version. ##### Rules that apply to every type - **Transaction type does not have to match.** A commission can create a transaction of a different type, and PalDock will create the conversion for it. See [Transaction type](https://paldock.com/knowledge-base/transaction-type/). - **`type` is required when creating** a conversion, and must match a type that is allowed on that channel. - **Click, lead, and send cannot carry an external ID.** It belongs to the advertiser’s order, which those types do not represent. - **A type can have several commissions.** Send the [Commission ID](https://paldock.com/knowledge-base/commission-id/) to say which one applies, otherwise the first one in the [order](https://paldock.com/knowledge-base/commission-order/) is used. --- ## Tracking pixel Pixel tracking places a small script on the advertiser’s confirmation page. When the page loads, the pixel fires and sends the conversion to PalDock through the visitor’s browser. It is the easiest method to deploy, but it runs in the browser, so it depends on cookies and can be blocked. Pair it with an [S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/) so you do not lose conversions when the pixel does not fire. ##### The two pixels - The **initiation pixel** goes on every page. It captures the click and remembers it. - The **conversion pixel** goes on the confirmation page only. It reports the conversion. Both are needed. Without the initiation pixel there is nothing to attribute the conversion to. There is also an **[update pixel](https://paldock.com/knowledge-base/update-pixel/)**, used to add URL and cookie data to a conversion that already exists. ##### Initiation pixel On every page load, this pixel reads the click ID from the URL, stores it for the length of your attribution window, and hands it to the conversion pixel later. That is what credits the conversion to the right affiliate. ``` `` ``` - **`t`**: your PalDock account identifier (slug). Required. - **`cookie`**: where the value is stored. `1` for a cookie (recommended), `2` for localStorage, `0` for sessionStorage. - **`expiration`**: the attribution window in minutes. `1440` is one day, `43200` is 30 days. Without it, 30 days is used. A conversion that happens after the window closes is not attributed. - **`pcidParam`**: the name of the URL parameter that carries the click ID. Without it, the pixel looks for `pcid`. **⚠️ Initiation scripts are versioned. When we release an update, you normally only change the version number in the script, not the implementation.** ##### Conversion pixel Placed on the confirmation page only. It creates the conversion and attaches everything needed for attribution and reporting. ``` `` ``` Required: **`action`**, **`type`**, **`advertiser_id`**, **`offer_id`**, and **`external_id`**. The most common optional ones: - **`result`**: approved or rejected. Without it, the transaction is created as pending. - **`value`**: the order value, used by percentage commissions. - **`commission`**: the payout amount, when the advertiser sends it directly. - **`commission_id`**: which commission applies, when the type has more than one. The full list is on [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). ##### Who the pixel belongs to The same conversion type has two pixel versions, and you pick the one that matches who places it. - **Advertisers** report conversions, so they can create and update. Requires the advertiser ID and the offer ID. - **Affiliate partners** enrich their own conversions with URL and cookie data, so they can only update. Requires the affiliate ID. Both are in **Workspace Settings, Tracking, Conversion types and pixels**. Pick the conversion type, then choose the advertiser or affiliate view. Custom types are added in the same place, and each of them gets its own pixel. ##### Matching the conversion The pixel needs to say which click or lead the conversion belongs to. - **Origin ID**, taken from the cookie by the initiation pixel, or passed explicitly. - **Advertiser ID with External ID**, when the advertiser has their own order ID. Affiliate links can only use the Origin ID, because the External ID does not exist yet at click time. iFrame and API integrations can use either. Sending both is safest. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/) and [Tracking processing](https://paldock.com/knowledge-base/tracking-processing/). ##### Using your own cookie If the advertiser does not want the PalDock initiation pixel, the conversion pixel can read the click ID from a cookie you control. - **`pcidCookie: 'custom_name'`** reads the value from your cookie instead of `pdc_pcid_[tenant-name]`. PalDock’s own cookie handling is then not used, and storing the click ID is up to you. - **`pcidCookieFallback: true`** falls back to the PalDock cookie when your cookie is empty. The default is false. `pcidCookie` cannot read **HttpOnly** cookies. Remove the flag or write a non-HttpOnly mirror cookie. To check: press F12, open the **Application** tab in Chrome or Edge, or **Storage** in Firefox, expand **Cookies**, select the domain, and look at the HttpOnly column. ##### The cookie The initiation pixel stores the value in `pdc_pcid_[tenant-name]`: ``` `{"pcid":"1245","expiration":1779778729419}` ``` The `expiration` timestamp comes from the expiration setting in the initiation pixel. **The cookie itself lives longer than that timestamp on purpose.** Always check the timestamp before using the value, not whether the cookie still exists. ##### Cookie consent - **⚠️ If you use Cookiebot or a similar tool**, set it to reload the page after consent, or at least to fire the scripts that were blocked. Otherwise the initiation pixel never runs, no click ID is stored, and you have to handle it yourself. - **The conversion pixel does not need consent.** It stores nothing in the browser, it only reports an event, so it falls outside cookie consent under GDPR. ##### Troubleshooting See [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/) for placement, triggers, ad blockers, and CSP problems. --- ## How to set up pixel tracking This page covers placing the pixel, choosing when it fires, and fixing it when it does not. ##### Where each pixel goes - **Initiation pixel**: on every page of the site. - **Conversion pixel**: only on the page that marks the conversion, whether pending or approved. It creates the conversion the moment it fires. - **[Update pixel](https://paldock.com/knowledge-base/update-pixel/)**: fires only when the data layer contains an Origin ID. We still recommend placing it on the conversion page as well. If you implement the pixel directly in the page, put it as high in the `` as possible. ##### Google Tag Manager GTM is the most common integration, though not the best one. Place both scripts as **Custom HTML tags**. ###### Which trigger to use GTM offers five triggers. The earlier the pixel fires, the more traffic it captures. **Use the Initialization trigger.** - **Consent Initialization**: fires first, and is meant for consent management tags only. Do not use it for the pixel. - **Initialization**: fires before everything except Consent Initialization. This is the one you want. - **Page View**: fires as the browser starts loading the page. - **DOM Ready**: fires once the page structure is built. - **Window Loaded**: fires once images and scripts have finished loading. Latest and least reliable. ###### Why GTM is not ideal Some ad blockers block the entire GTM container, and the pixel goes with it. Server-side GTM survives most of them, standard GTM does not. - **Adblock**: does not block either setup. - **Adblock Plus, uBlock Origin, Ghostery**: block standard GTM and server-side GTM alike. - **Safari ITP**: affects standard GTM, not server-side GTM. - **Corporate VPNs**: usually affect standard GTM. Behaviour varies by network. The safer options, in order: put the pixel directly in the page code, use server-side GTM, or accept standard GTM and back it up with a postback. ##### When the pixel is blocked Set up an **[S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/)** alongside the pixel. It runs server to server, so ad blockers and missing cookie consent do not affect it. - Fire it **when the conversion is created**, so both methods report the same event and PalDock keeps one conversion. - Or fire it **only on updates**, when the advertiser approves or rejects. Deduplication on the [external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) is what keeps the two methods from doubling your numbers, so make sure the advertiser sends it in both. ##### Where the click ID is stored The `cookie` parameter of the initiation pixel decides this. - **`cookie=1`**: a cookie. Recommended. - **`cookie=2`**: localStorage. - **`cookie=0`**: sessionStorage. **⚠️ localStorage and sessionStorage are not shared across domains or subdomains.** They only work within the exact same origin, meaning the same protocol, domain, and port. If your homepage runs on the main domain and checkout on a subdomain, only a cookie carries the click ID across. If you cannot fire the pixel before cookie consent, you have to move the value yourself, for example through a URL parameter or your own backend. ##### Troubleshooting ###### The pixel never appears in the network tab Your site may have a **Content-Security-Policy** header that blocks our domain. The pixel then fails silently: nothing in the browser’s Network tab, while GTM still reports the tag as fired. To confirm, open DevTools, Console, and look for a message about a refused script and a Content Security Policy directive. To fix it, ask your developers to add our domains to the CSP: ``` `connect-src 'self' https://*.paldock.com https://paldock.com https://*.palpxl.com https://palpxl.com;` ``` Then check in DevTools, Network, that the requests go through. ###### The pixel fires but nothing arrives Check the [tracking log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/). If the request is not there, it never reached PalDock, so the cause is in the browser: CSP, an ad blocker, or a missing consent. If it is there but did nothing, read the outcome in [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). ###### Conversions appear without an affiliate The initiation pixel is not firing, or is firing after the click ID is gone from the URL. Check that it is on every page and on the Initialization trigger. --- ## Tracking S2S Postback An S2S postback is a request the advertiser’s server sends directly to PalDock. No browser, no cookies, nothing to block. It is the most reliable way to receive conversions and the method we recommend to every advertiser, on its own or alongside a [pixel](https://paldock.com/knowledge-base/tracking-pixel/). ##### The endpoint ``` `https://api.paldock.com/api/tenant-name/postbacks/handle` ``` Three ways to identify the conversion: ###### By Origin ID ``` `?origin_id={origin_id}&type={sale}&result={approved}&action={create}` ``` ###### By Advertiser ID and External ID ``` `?advertiser_id={advertiser_id}&external_id={your_external_id}&type={sale}&result={approved}&action={create}` ``` ###### By both, which we recommend ``` `?origin_id={origin_id}&advertiser_id={advertiser_id}&external_id={your_external_id}&type={sale}&result={approved}&action={create}` ``` Affiliate links can only use the Origin ID, because the external ID does not exist yet at click time. iFrame and API integrations can use either. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### The main parameters - **`type`**: the conversion type. Required when creating. - **`action`**: `create` or `update`. Without it, the request is treated as a create. - **`result`**: `approved`, `rejected`, or `pending`. Sending it on an update changes the transaction result. - **`value`**: the order value, used by percentage commissions. - **`commission`**: the payout amount, when the advertiser calculates it themselves. - **`external_id`**: the advertiser’s own order ID. Always ask for it, even when the Origin ID is sent. - **`commission_id`**: which commission applies, when the type has more than one. - **`postback_id`**: which postback the request belongs to. Required when that postback has a scenario. - **`create=false`**: refuse to create anything if the update finds no conversion. The full list is on [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). ##### Postbacks and conditions A **global postback** exists by default with every condition set to All, so an advertiser can start sending immediately. Create your own when you need different handling for different partners. Conditions decide whether a request is accepted: - **Source**: All, Link, iFrame, API - **Conversion type**: All, Prospect, Sale, or a custom type - **Affiliate**: All or specific - **Advertiser**: All or specific - **Offer**: All or specific A request that does not match the conditions is logged as Filtered and nothing happens. Postbacks appear in the postback table with the country inherited from the offer. When no offer or several offers are selected, the global country applies and the category stays blank. ##### Scenarios Some advertisers only tell you that something changed, without saying what. A scenario lets the postback call them back and fetch the rest, or transform the incoming data before it is stored. Two common uses: - **Fetching missing data**: the advertiser sends an ID, PalDock calls their API for the status and the value. - **Mapping parameter names**: the advertiser sends their own names and their own status values, and the scenario translates them into PalDock’s. **⚠️ When a postback has a scenario, `postback_id` becomes mandatory.** Without it the request is still received, but the scenario does not run. Ask the advertiser to add it to the URL, for example `?postback_id=value`. See [Connection Creator in Tracking](https://paldock.com/knowledge-base/connection-creator-in-tracking/). ##### Creating and updating - **Create** records a new conversion and needs `type`. - **Update** changes an existing one, typically to set the result or the value. - An **update that finds no conversion** creates one instead, as long as `type` is present and `create=false` is not. An advertiser who reports a sale on a click or a lead does not overwrite it. PalDock creates a sale conversion under it. See [Tracking processing](https://paldock.com/knowledge-base/tracking-processing/). ##### What comes back - **200**: something changed. - **204**: accepted, but nothing changed. Usually the values were already stored. - **400**: an update that found no conversion. - **422**: the request failed validation. Treat 204 as a warning. See [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). --- ## Tracking API The Tracking API is a server-to-server connection that PalDock initiates. It calls the advertiser’s system to ask about a conversion, or sends conversion data out to an affiliate’s system. No browser, no cookies. It is built on the [Connection Creator](https://paldock.com/knowledge-base/topics/connection-creator/), so it has all the same features, tuned for tracking. See [Connection Creator in Tracking](https://paldock.com/knowledge-base/connection-creator-in-tracking/). Two audiences use it: - **Admins**, to call the advertiser and retrieve the status of a conversion. - **Affiliate partners**, to forward conversion data into their own systems. ##### The parameters The Tracking API works with the same conversion parameters as pixels and postbacks. Which parameter is available in which direction is listed on [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). For the placeholders you insert into the request itself, see [Parameters](https://paldock.com/knowledge-base/parameters/). ##### Conditions Conditions decide whether a Tracking API runs for a given conversion. Each is All by default. - **Source**: All, Link, iFrame, API - **Conversion type**: All, Lead, Send, Prospect, Sale, or a custom type - **Affiliate**: All or specific - **Advertiser**: All or specific - **Integration**: All or specific - **Channel**: All or specific - **Included offers** and **Excluded offers**: All or specific - **Result**: Not chosen, All, or specific The result condition is the one that changes the most. Set it, and only conversions that produced a transaction are sent. Leave it unset, and every conversion is sent, including those with no payout. Tracking APIs appear in the Tracking API table with the country inherited from the offer. When no offer or several offers are selected, the global country applies and the category stays blank. ##### Triggers The trigger decides **when** it fires, the conditions decide **whether**. - **All**: any change to a transaction, created or updated. This is the default. - **Created**: only when a transaction is created. - **Updated**: only when an existing transaction is updated. Which one to pick: - **Calls to advertisers**: usually **Created**. With All, the call runs on creation, receives a status, updates the transaction, and that update triggers it again. - **Postbacks to affiliates**: usually **All**, narrowed with conditions. ###### What fires when - **A click is created**: All, Created - **A sale is created with no commission applied**: All, Created - **A sale is created and a transaction with it**: All, Created - **A lead is created through an iFrame and immediately updated with cookie data by a pixel**: All, Created, and then All, Updated for the update. The update is a separate event with its own trigger. - **A sale is updated with a new value**: All, Updated - **The same sale is updated again with a new result**: All, Updated **⚡ If you are not sure, use the All trigger and narrow it with conditions.** - Only approved transactions: trigger **All**, condition result is Approved. - Only approved transactions that already carry cookie data: trigger **Updated**, condition result is Approved. The cookie data arrives with the update, so the creation event is too early. ##### Affiliate postbacks A Tracking API created by an affiliate appears in their **Affiliate Postback** section. One created by an admin does not, even when it is limited to a single affiliate with a condition. Those stay visible to admins only. See [Affiliate postback](https://paldock.com/knowledge-base/affiliate-postback/). ###### How many requests an affiliate receives PalDock forwards changes as they happen, so an affiliate normally receives two requests per conversion: one when it is created, one when the result arrives. - **On creation**, the affiliate is notified immediately. The result is usually pending. - **With [auto-approve](https://paldock.com/knowledge-base/auto-approve-transactions/)**, the result is Approved right away and the affiliate receives that immediately as well. - **On updates from the advertiser**, such as an approval, a rejection, or a change of amount, PalDock forwards each one. - **With several commissions**, each transaction is sent separately. The affiliate has to aggregate them. Two ways to cut the volume: - **Filter on result**, so pending transactions are not sent at all. - **Delay the postback**, so the affiliate gets one final update once the conversion is settled. Fewer requests, later reporting. ##### Timeouts and retries Each request has a timeout, and you can set how many times it may be retried. Retries are what make it possible to keep asking an advertiser until a pending conversion is decided. Current values are on [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ##### One advertiser, several tokens When a Pingtree has several channels from the same advertiser and each needs its own authorization token, one Tracking API cannot cover them all. Duplicate it per channel and give each copy the right token. ##### When it does not work Every call is recorded in the tracking log with its response. See [Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/) and [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). --- ## Manual Tracking and Transaction Import Manual import is the fallback when no automated method is available: an advertiser who cannot implement a pixel or a postback, a batch that arrived by email, or a correction after something went wrong. Import is in **Reports, Transactions**. ##### What an import does An imported row behaves exactly like a tracking request, so it can do two things. - **Create**: a new conversion is recorded. Commissions run on it and produce transactions. - **Update**: an existing conversion is changed, typically to set the result or the value. The transactions under it are updated. You do not create transactions directly. You import the conversion, and the [commission](https://paldock.com/knowledge-base/topics/commissions/) creates the transaction under it. Rows that match no commission are still imported, they just produce no payout. ##### Before you start - Make sure the **commissions are set up** and active for the conversion type you are importing. - Decide which **identifier** each row will carry. Without one, nothing can be matched. - Download the **template** and test with a few rows before importing a large batch. ##### What each row can contain - **Origin ID**: links the row to the original click or lead. - **External ID**: the advertiser’s own order ID. Needed for deduplication and for updating later. - **Conversion date** (optional): the date the conversion happened. Without it, the current date is used. - **Result** (optional): pending, approved, or rejected, applied to the transaction. An update needs to point at exactly one conversion. When several conversions exist under the same origin, the Origin ID alone is not enough and you have to send the external ID as well. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### What happens after the upload Each row goes through the same steps as a postback or a pixel request. - The conversion is recorded or found. - [Deduplication on the advertiser’s external ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) applies. A row for an order that already exists is stored as a duplicate and produces nothing. - [Commissions](https://paldock.com/knowledge-base/commission-selection/) run, with their conditions, active periods, and [recurrence limits](https://paldock.com/knowledge-base/recurrence-type/). - Matching rows produce transactions, which appear in the transaction report. Nothing about an imported conversion is treated differently later. A postback can still update it, and it counts towards recurrence limits and deduplication like any other. ##### When rows produce no transaction Check the [conversion log](https://paldock.com/knowledge-base/tracking-and-conversion-logs/) first, then work through the usual causes: - No commission matches that conversion type. - The commission is inactive or outside its active period. - The recurrence limit was already reached. - The row was deduplicated on the external ID. - The row was an update that found no conversion to update. See [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). --- ## Tracking parameters Every tracking method moves the same set of parameters. What differs is the direction and which parameters are available in it. - **Pixel** and **S2S postback** bring data into PalDock, usually from the advertiser. - **Tracking API** and **affiliate postback** send data out of PalDock, to the advertiser or to the affiliate. This page is the reference for what may travel in each direction. For what you can pick while building a scenario in the Connection Creator, see [Parameters](https://paldock.com/knowledge-base/parameters/). #### The identifiers Four parameters decide whether a tracking request matches anything at all, so read these before the rest: - `origin_id` is the click or the lead. - `send_id` is one delivery of that lead to one channel in a pingtree. One lead can have several. - `conversion_id` is the sale or the prospect. One origin can have several. - `external_id` is the advertiser’s own ID for the order, sent together with `advertiser_id`. To create a conversion, send the `origin_id`, or the `advertiser_id` together with the `external_id`. Sending both pairs is the safest option. To update one, send the `external_id` with the `advertiser_id`, or the `conversion_id` when you have it. Full detail on which to send and when: [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). #### The full list A ✅ means the parameter can be used in that direction, a ❌ means it cannot. The first column is the group the parameter belongs to, so you can sort the table by it. | Group | Parameter | Pixel | S2S postback | Tracking API | Affiliate postback | Description | | --- | --- | --- | --- | --- | --- | --- | | Conversion | origin_id | ✅ | ✅ | ✅ | ✅ | PalDock ID of the click or the lead. Use it to attribute a conversion back to the affiliate. | | Conversion | send_id | ✅ | ✅ | ✅ | ✅ | PalDock ID of one delivery of a lead to one channel in a pingtree. One lead can have several. | | Conversion | conversion_id | ❌ | ❌ | ✅ | ✅ | PalDock ID of the sale or the prospect. One origin can have several. | | Conversion | external_id | ✅ | ✅ | ✅ | ✅ | The advertiser’s own ID for the order. | | Conversion | affcid | ✅ | ✅ | ✅ | ✅ | The affiliate’s own ID for the conversion. | | Conversion | action | ✅ | ✅ | ✅ | ✅ | Whether to create a new conversion or update an existing one. | | Conversion | type | ✅ | ✅ | ✅ | ✅ | The conversion type. Required when action is create. | | Conversion | result | ✅ | ✅ | ✅ | ✅ | The transaction result, such as pending, approved or rejected. | | Conversion | ip_address | ❌ | ❌ | ✅ | ✅ | IP address of the end user. | | Commission | value | ✅ | ✅ | ✅ | ✅ | The order value. Used when the commission is a percentage of it. | | Commission | commission | ✅ | ✅ | ❌ | ❌ | The amount the advertiser sent in their commission parameter. | | Commission | adv_commission | ❌ | ❌ | ✅ | ❌ | The final commission from the advertiser. | | Commission | aff_commission | ❌ | ❌ | ✅ | ✅ | The final commission for the affiliate. | | Commission | commission_profit | ❌ | ❌ | ✅ | ❌ | The difference between adv_commission and aff_commission. | | Commission | commission_id | ✅ | ✅ | ✅ | ❌ | Which commission applies, when several exist for the same type. | | Commission | commission_code | ✅ | ✅ | ✅ | ❌ | The commission’s own text code. Works as an alias for commission_id. | | Commission | currency | ❌ | ❌ | ✅ | ✅ | The currency of the offer, in ISO 4217 format. | | Commission | price | ❌ | ❌ | ✅ | ❌ | The price the advertiser bid. Used in auction distribution. | | Offer | offer_id | ✅ | ✅ | ✅ | ✅ | The ID of the offer. | | Offer | offer_name | ❌ | ❌ | ✅ | ✅ | The name of the offer. | | Offer | country | ❌ | ❌ | ✅ | ✅ | The country of the offer, in ISO 3166 format. | | Advertiser | advertiser_id | ✅ | ✅ | ✅ | ✅ | The ID of the advertiser. | | Advertiser | advertiser_name | ❌ | ❌ | ✅ | ❌ | The advertiser’s nickname. | | Advertiser | advs1 to advs10 | ✅ | ✅ | ✅ | ❌ | Ten free slots for values belonging to the advertiser. | | Affiliate | owner_id | ✅ | ✅ | ✅ | ✅ | The ID of the affiliate. | | Affiliate | owner_name | ❌ | ❌ | ✅ | ❌ | The affiliate’s nickname. | | Affiliate | affs1 to affs10 | ✅ | ✅ | ✅ | ✅ | Ten free slots for values belonging to the affiliate. | | Integration | integration_name | ❌ | ❌ | ✅ | ❌ | The name of the integration. | | Integration | channel_name | ❌ | ❌ | ✅ | ❌ | The channel name from the pingtree. | | Integration | channel_visible_name | ❌ | ❌ | ✅ | ❌ | The channel name the customer sees. | | Integration | postback_id | ✅ | ✅ | ✅ | ❌ | The postback the flow belongs to. Works only when there are follow-up steps. | | Integration | redirect_url | ❌ | ❌ | ✅ | ❌ | Where the customer goes next. Comes from the advertiser in the integration. | | Time | created_date | ❌ | ❌ | ✅ | ✅ | When the conversion was created, in Y-m-d H:i:s format. | | Time | timestamp | ❌ | ❌ | ✅ | ✅ | The same moment as a Unix timestamp. | | Time | timestamp_sign | ❌ | ❌ | ✅ | ✅ | The timestamp used when signing a request. | | Form data | data_XYZ | ❌ | ❌ | ✅ | ❌ | Any field from the form structure, with data_ in front of its system name. | | Custom | custom_XYZ | ✅ | ✅ | ✅ | ✅ | Any parameter sent with the custom_ prefix is stored. | | Cookies | custom_cookie_ga | ✅ | ✅ | ✅ | ✅ | Google identifier from the cookie. | | Cookies | custom_cookie_ga_container_id | ✅ | ✅ | ✅ | ✅ | Google container identifier from the cookie. | | Cookies | custom_cookie_gcl_aw | ✅ | ✅ | ✅ | ✅ | Google Ads click identifier from the cookie. | | Cookies | custom_cookie_fbp | ✅ | ✅ | ✅ | ✅ | Facebook identifier from the cookie. | | Cookies | custom_cookie_fbc | ✅ | ✅ | ✅ | ✅ | Facebook identifier from the cookie. | | Execution | random_uuid | ❌ | ✅ | ✅ | ✅ | A fresh random identifier, generated for each request. | #### Parameters with a prefix Two entries in the table are patterns rather than fixed names: - `data_XYZ` is any field from the form structure, with `data_` in front of its system name. A field called `email` is sent as `data_email`. See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). - `custom_XYZ` is anything you send with a `custom_` prefix. PalDock stores it whether or not it is defined anywhere, which makes it the place to put values that have no parameter of their own. The `custom_cookie_` parameters are separate from these. They carry advertising platform identifiers collected in the visitor’s browser, and the names are fixed. Forward them when you send conversions into Google or Facebook, which need their own identifier to match the conversion to the click. #### Where to see what was sent Every tracking request is recorded with the parameters it carried. See [Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/), and [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/) when a request did not do what you expected. --- ## Tracking by vouchers #### Tracking by vouchers A voucher is a discount code the customer enters at checkout. Assign a code to an affiliate, and any conversion that uses it is credited to that affiliate. Vouchers are useful where links do not reach: influencers reading a code out loud, printed materials, podcasts, or anywhere the customer arrives without clicking anything. ##### Creating vouchers Vouchers are managed in **Tracking, Vouchers**. - Create them one by one in the table, or import them in bulk. - Once created, they can be used in tracking and appear in reports. ##### How they are tracked A voucher is **not a separate tracking method**. The conversion still arrives through a [pixel](https://paldock.com/knowledge-base/tracking-pixel/), a [postback](https://paldock.com/knowledge-base/tracking-s2s-postback/), or the [Tracking API](https://paldock.com/knowledge-base/tracking-api/), and the code travels with it. The advertiser has to send the code the customer used, so agree on that before you hand out any vouchers. ##### Attribution **⚠️ A voucher always wins. When a conversion carries a code that belongs to an affiliate, that affiliate owns the conversion, whatever the click said.** Example: - A visitor clicks Affiliate A’s link and later buys something. - At checkout they enter a voucher that belongs to Affiliate B. - The conversion is credited to **Affiliate B**. This is deliberate. Entering a code is a stronger signal than an old click, because the customer had to get it from somewhere. Worth knowing before you roll them out: - A code shared publicly, on a coupon site for example, will pull in conversions that other affiliates brought. Give codes only to partners who are meant to be credited for them. - **Everything else follows the conversion as usual.** The voucher changes who owns it, not which offer, commission, or amount applies. --- ## Tracking and Conversion Logs Two logs, two questions. - The **tracking log** answers “did the request arrive and what did it do”. - The **conversion log** answers “what exists in PalDock now and did it produce a payout”. Start with the tracking log when something is missing, and move to the conversion log once you know the request arrived. ##### Tracking log Records every [S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/), [pixel](https://paldock.com/knowledge-base/tracking-pixel/), and [Tracking API](https://paldock.com/knowledge-base/tracking-api/) request. One row is one flow, and expanding it shows all the individual requests inside. What appears in it: - **S2S postback**: requests received from advertisers. - **Tracking API**: requests PalDock sends to advertisers. - **Tracking pixel**: requests fired by pixel placements. - **Affiliate postback**: outgoing requests that affiliates configured themselves. Affiliates see only their own. What each row tells you: - **State**: whether the request was accepted or refused. - **Details and reason**: the refusal reason, or the processing outcome when it was accepted. - **The requests inside the flow**, when one incoming request triggered several calls. For what each outcome means and what to do about it, see [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). ##### Conversion log A consolidated view of every conversion PalDock holds, whatever created it: postback, pixel, Tracking API, manual import, or PalDock itself. What each row tells you: - **Origin ID, Send ID, Conversion ID, Transaction ID**: the whole chain, so you can follow one journey end to end. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). - **State**: whether the conversion is valid, and whether it produced a transaction. - **Transactions**: how many were created and under which commission. One conversion can have several. ##### Why a conversion produced no transaction - The conversion **matches no commission**, usually because of the conversion type. - The commission is **inactive** or outside its active period. - The **[recurrence limit](https://paldock.com/knowledge-base/recurrence-type/)** was reached. - It was **[deduplicated](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/)** on the advertiser’s external ID. - The conversion is **not valid**, for example refused by validation, by a filter, or by the Pingtree. - The conversion was **created by a commission**. Those never trigger commissions again. See [Transaction type](https://paldock.com/knowledge-base/transaction-type/). Full list of states and what they mean: [Tracking errors and reasons](https://paldock.com/knowledge-base/tracking-errors-and-reasons/). Commission side: [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). ##### Conversions you did not create Some rows in the conversion log were created by PalDock, not by a tracking request. - A commission whose [transaction type](https://paldock.com/knowledge-base/transaction-type/) differs from the conversion creates the matching conversion and puts the transaction there. - The original conversion then carries no transaction, and the new one does. This is expected. Look at the transaction, not at the conversion that triggered it. ##### Which log to use - **Debugging a request**: tracking log. Is it there, was it accepted, what did it say. - **Confirming a result**: conversion log. What was recorded, is it valid, how many transactions came out of it. --- ## Affiliate postback Affiliates can forward their own conversion data into any external system. In PalDock this is a [Tracking API](https://paldock.com/knowledge-base/tracking-api/) that the affiliate creates and manages in the **Affiliate Postback** section. Typical uses: - Sending conversions into your own tracker or reporting tool. - Passing conversions on to an upstream network. - Firing conversions into ad platforms so campaigns can optimise on them. ##### What an affiliate can set - **The URL** the data is sent to, and the parameters that go with it. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). - **Conditions**, so only some conversions are sent, most often a condition on offer or on result. - **A trigger**, deciding whether it fires when a transaction is created, when it is updated, or both. ##### Two things worth knowing - **You normally receive two requests per conversion**, one when it is created with a pending result, and one when the advertiser decides it. Filter on result if you only want the final one. - **Several commissions mean several requests.** Each transaction is sent separately, so aggregate them on your side. ##### What you cannot see Postbacks an admin created are not listed here, even when they are limited to your account. You only see the ones you created yourself. Full detail on conditions, triggers, retries, and timeouts is on the [Tracking API](https://paldock.com/knowledge-base/tracking-api/) page. --- ## Origin Deduplication Origins are clicks and leads, the first record of a visitor. PalDock counts one visitor once, so repeated clicks and repeated submissions do not inflate your numbers. This is not the same as [deduplication based on the advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/), which stops an advertiser reporting the same order twice. That happens later, on the conversion. Origin deduplication happens at the start, and it needs no external ID. Nothing is deleted. Duplicates are stored and marked, so you can always see what arrived and what was counted. ##### Click deduplication Each click is compared against the previous ones. It is marked as a duplicate when **all** of these match: - **Same IP address** - **Same user agent** - **Same offer** - **Same affiliate** - **Within 1 hour** of the original click Together these form the visitor’s fingerprint. The window is fixed at one hour and cannot be changed. The visitor is still redirected as normal. The click simply does not count as a new one. **A unique affiliate click ID does not change this.** A click carrying its own `cid` is still a duplicate if the fingerprint matches. A new ID does not make a new visitor. ##### Lead deduplication Leads work differently, because the same person can legitimately send several leads. PalDock separates two questions: was this lead sent twice by mistake, and have we seen this person before. ###### Duplicate leads A lead is treated as a duplicate when **all** of these match: - **Same offer** - **Same affiliate** - **Same form data**, all filled fields identical - **Within the duplicate window**, 5 minutes by default A duplicate lead is stored with the state **Failed** and the reason **Duplicate**. It is not distributed, not paid on, and not counted in your lead totals. Two things worth knowing: - **The window runs from a successful lead only.** If a lead fails and the affiliate corrects it and resends, the corrected one goes through. Only accepted leads block a repeat. - **Any change to the data makes it a new lead.** This check looks at the whole form, so a single corrected digit means it is no longer the same lead. The window is set in **Workspace Settings**. Raising it above a few minutes rarely helps. If you want to refuse people you accepted last month, that is lead uniqueness, below. ###### Lead uniqueness Uniqueness answers whether this person has appeared in this product before, over days or months rather than minutes. - **The identifier is a field or a combination of fields** you choose, because what identifies a person differs by product. Email and phone by default, a national ID number for loans, a licence plate for car insurance, address and email for utilities. - **It is set on the structure**, since that is where the fields live, and the behaviour is set on the offer or product. A workspace default applies where nothing more specific is set. - **The affiliate is not part of the match.** The question is whether you have this person, not whether that partner brought them before. - **The window is configurable**, 90 days by default, or lifetime. PalDock records two states for each lead: - **Seen**: this person already appeared in the product, in any state. - **Sent**: this person was already delivered to an advertiser. Uniqueness on its own changes nothing. It marks the lead and makes it available to filters, where you decide whether to refuse repeat leads, and to reports. The identifier is stored as a hash, never as the raw value, so anonymising a lead does not break uniqueness. ###### Related leads One person often produces several leads in a short time, for example when an affiliate queries several offers in sequence, or sends the same person to a different product. These are not duplicates and they are all processed normally. They are linked to the first one, and the lead log has a filter to show only the first lead of each group, so a person who generated twenty rows can be read as one. ##### What your reports show Three metrics, three meanings: - **Gross clicks and gross leads**: everything that arrived, duplicates included. - **Clicks and leads**: what was counted, after duplicates. - **Unique leads**: how many of those were the first from that person in the product. Your own numbers may be higher than ours. Two events on your side can resolve to one here. Nothing is lost, the same person is counted once, which is the point. ##### When it gets in the way - **Testing.** Repeated test clicks from one machine collapse into one, and repeated test leads with identical data are refused. Change the network or the browser, vary the form data, or wait out the window. - **Shared networks.** Visitors behind one office or mobile gateway share an IP, but the user agent usually differs, so genuine visitors stay separate. - **Legitimate repeat customers.** Someone who really does apply twice in five minutes is refused. That is the trade-off of a short window, and it is why the window is short. --- ## Update pixel The update pixel adds data to a conversion that already exists. It does not create anything. It is placed either by the **advertiser** on the conversion page, or by the **affiliate** on their form page, to collect URL and cookie values that an iFrame or API form cannot pick up on its own. **⚠️ Tracking cannot create Lead conversions. It can only update existing ones. New leads must come from the form or the API.** ##### The script ``` `` ``` ##### What it collects - **`queryParam`**: values from the URL, typically utm tags. - **`cookieParam`**: values from cookies, typically Google and Meta identifiers such as `_ga`, `_fbp`, and `_fbc`. Up to three keys each. Once they are on the conversion, you can forward them anywhere through the [Tracking API](https://paldock.com/knowledge-base/tracking-api/), for example into Google Ads or Meta. ##### Which conversion gets updated Two ways to point at it: - **Origin ID** = **pldk_conversion_id**, on its own. Always available, to advertisers and affiliates alike. - **Advertiser ID with External ID**, for advertisers only. If two conversion types happen in the same session, add **`type`** so PalDock knows which one you mean. Use `lead` rather than `prospect` when you are updating the original lead, not the transaction. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### Where the Origin ID comes from Every conversion has one, and you need it later to update that conversion. Where you get it depends on how the conversion was created. - **Created by a pixel**: the pixel writes the Origin ID into the data layer automatically. - **Created through the API or a postback**: the response contains it. Store it, then push it to the data layer yourself. ``` `{"status": "accepted", "origin_id": "1234"}` ``` ``` `window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'sale', pldk_conversion_id: id // origin ID received from the pixel or the API });` ``` Use the same `event` name as the conversion type you created. Who has to do what: - **Affiliates using an iFrame form**: nothing. The form handles it. - **Affiliates using an API form, and all advertisers**: store the Origin ID and push it to the data layer, or pass it in the pixel code. When the value is in the data layer, the update pixel picks it up on its own and you can leave `origin_id` out of the script. ##### Where to place it - On the **conversion page**, alongside the conversion pixel. - The update pixel only fires when an Origin ID is available, so placing it on other pages does nothing. See [How to set up pixel tracking](https://paldock.com/knowledge-base/how-to-set-up-pixel-tracking/). --- ## Tracking errors and reasons When a tracking request does not do what you expected, PalDock records why in two places. - The **tracking log** records what happened to the request itself. - The **conversion log** records what happened to the conversion the request created. A request can be accepted and the conversion still end up invalid, so always check both. See [Tracking and Conversion Logs](https://paldock.com/knowledge-base/tracking-and-conversion-logs/). ##### What the endpoint returns - **200 OK**: the request changed something, either the conversion or its transaction. - **204 No Content**: the request was accepted, but nothing changed. Usually the values sent were the same as the ones already stored. - **400 Bad Request**: an update request that could not find the conversion to update. - **422 Unprocessable Entity**: the request failed validation, for example a missing identifier or an unknown conversion type. Treat 204 as a warning rather than a success. It means the advertiser is sending data that has no effect. ##### Request outcomes in the tracking log - **Ok**: the request was processed and something changed. - **No change**: the request was valid but nothing needed updating. - **Unmatched**: PalDock could not find the conversion the request refers to. This is the most common failure. See below. - **Filtered**: the request did not meet the conditions of the postback it was sent to, for example the wrong source, offer, or advertiser. - **In progress**: a scenario is still running. The final outcome is recorded when it finishes. - **Fail**: the request or the scenario ended with an error. The log row carries the error message. ###### Why a request comes back Unmatched - The **Origin ID** was wrong, expired, or belonged to a different workspace. - Only the **External ID** was sent, without the **Advertiser ID**. On its own the External ID is not unique. - The conversion the advertiser refers to was **never created**, for example because the pixel was blocked. - Several conversions match the identifier and PalDock cannot tell which one is meant. See [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### Conversion statuses Some statuses mean the conversion is fine (status ok), others mean it is invalid (status fail). An invalid conversion is stored and visible, but **no commission runs on it, so no transaction is created**. ##### Checklist when nothing happens - Find the request in the **tracking log**. If it is not there at all, it never reached PalDock. Check the pixel, the CSP, or the advertiser’s firewall. - If the outcome is **Filtered**, compare the request against the conditions on that postback. - If it is **Unmatched**, check which identifiers the advertiser is sending. - If it is **Ok** or **No change**, move to the **conversion log** and read the status. - If the conversion is valid but there is still no transaction, the cause is on the commission side. See [How PalDock picks a commission](https://paldock.com/knowledge-base/commission-selection/). --- # Structures ## About structures Structures define the format of data collected and processed in PalDock. They describe which fields are included, how those fields behave, and how the data is used across forms, APIs, feeds, and integrations. By using structures, you ensure that all data in PalDock is consistent and reusable. ###### Types of Structures - [Form Structure](https://paldock.com/knowledge-base/form-structure/) – defines the fields collected when a lead is created. Used in forms, APIs, and partner integrations. - [User Structure](https://paldock.com/knowledge-base/user-structure/) – defines the fields collected when users register or manage their account. Separate structures exist for Affiliate partners and Advertisers. - [Feed Structure](https://paldock.com/knowledge-base/feed-structure/) – defines the format of product feeds (e.g. product name, price, availability) imported into PalDock and used in affiliate display or lead distribution. ###### Fields in Structures Each structure is made of **fields**. Fields determine what kind of data is collected (e.g. text, number, email). To keep structures consistent and avoid duplication, PalDock supports three levels of fields: - **Global fields** – predefined system fields used across all workspaces (e.g. First Name, Email). - **Local fields** – workspace-wide fields created by admins, reusable across multiple structures. - **Custom fields** – fields created directly inside one structure, specific to that structure. 👉 We recommend using [global fields](https://paldock.com/knowledge-base/local-versus-global-fields/) whenever possible, and local or custom fields only when necessary. ###### How structures are used A structure on its own collects nothing. It becomes active when something is attached to it: - A **form structure is attached to an offer**, and an offer can have more than one. That is how two landing pages that differ by a single field share one offer. See [Multiple Structures for Offers and Integrations](https://paldock.com/knowledge-base/multiple-structures-for-offers-and-integrations/). - An **integration is built on exactly one structure**. The fields in that structure are what you map into the advertiser’s request. - A **user structure is used by the registration and account forms** for affiliate partners and advertisers, so it is not attached to anything. The same structure serves the form, the [embeddable form](https://paldock.com/knowledge-base/embeddable-form/) and the [API](https://paldock.com/knowledge-base/api-integration/). A field added to the structure appears in all three, and in the API documentation your partners see. ###### Advanced Options All structures can use the same advanced features: - **Field settings** – define labels, placeholders, default values, and visibility rules. - **Validation** – enforce correct data formats or check values against external services. - **Modify** – fill or transform a field value, either from another field or from an external service. - **AutoComplete** – suggest values to the user while they are typing. - **Translations** – localize field labels and placeholders into multiple languages. ⚠️ **Validation, Modify and AutoComplete are powerful features, but because they can rely on external services, a misconfiguration can break the entire system, preventing the form from being submitted and the lead from being created.** --- ## Local, Global and Custom fields ##### Local, Global and Custom fields Fields define what can be collected in a form and what travels onwards with the lead. PalDock has three levels of them, and the difference is who defines them and how widely they apply. - **Global fields** are defined by PalDock and exist in every workspace. - **Local fields** are defined by an admin and exist in one workspace. - **Custom fields** are defined inside one structure and exist only there. ###### Use global fields wherever you can This is the one recommendation worth taking from this page. - **Integrations from the library work immediately.** They are built against global fields, so an integration you add from the library can be ready as soon as you fill in a token, instead of after an hour of mapping. Every advertiser you add later is the same. - **Leads move between workspaces without mapping.** When you send a lead to another PalDock workspace and both sides use global fields, the fields line up on their own. With custom fields, someone has to map them by hand, on both sides, and again whenever either side changes something. - **Reporting stays comparable.** Email exports into the same column no matter which form or workspace the lead came from. - **Your partners save the same work you do.** A structure built on global fields is one an affiliate or an advertiser can connect to without asking you what each field means. The cost of not doing it is not one big decision. It is a small amount of mapping repeated in every integration, every export and every new partner, for as long as the workspace exists. So use a global field wherever one fits, a local field when none does, and a custom field only for something genuinely one off. ###### Global fields Global fields are the same in every PalDock workspace: same system name, same type, same meaning. First name, last name, email, phone, address, and many more. Because they are the same everywhere, nobody has to map them. That is what makes the library and cross-workspace delivery work. **Some of them belong to the person, not to you.** First name, last name and email are linked to the user’s [account](https://paldock.com/knowledge-base/one-account-multiple-workspaces/), which spans every workspace they have access to. When the user changes their name, it changes everywhere, and an admin cannot change it for them. That is deliberate: the same person should not be called two different things in two workspaces. This applies to the fields tied to the account. A global field describing a lead, such as an amount or a product, behaves like any other field. **Global fields use the `g_` prefix**, so a global email is `g_email`. The prefix is reserved and nothing else in the workspace can use it. It also replaces the `data_` prefix that fields defined in a structure carry, so in a scenario a global field is written as `{g_email}`, not `{data_g_email}`. You cannot edit a global field. If you need one that behaves differently, make a local field instead, and accept that it will not be linked to the account. ###### Local fields Local fields are yours. You define them once in the workspace and reuse them across every structure, instead of building the same field again in each form. They are for what global fields do not cover, and for anything specific to how you work. - They can be edited and customised freely. - Once created, they appear in a list and can be picked in any structure. - When you use one in a structure, PalDock applies the prefix and locks the field name, so the same field cannot drift into two spellings. A local field can still be modified inside a particular structure, so one structure can format it differently while the definition stays shared. The structure shows an icon when that is happening. ###### Custom fields Custom fields live inside a single structure and nowhere else. They are fully editable and quick to make, which is exactly why they multiply. Before making one, check whether a global field already covers it and whether a local field would serve the next form too. Use them for what is genuinely unique to one form. ###### Creating a field - **In a structure**, click **Add** and the field is created as a custom field, ready to use immediately. - **In the workspace**, open the local fields section in Settings and click **Add**. This is the full editor, the same as in a structure. You can also create a local field without leaving a structure: pick the local option and click **Add**. It is a shorter form, and the new field appears in the list of local fields straight away, ready for every other structure. ###### Using a local or global field in a structure Instead of adding a new field, click the selection icon, the dashed square next to the field name. A panel opens with everything available, and you can search it by typing. Choose one and the field name is filled in and locked, with the prefix applied. The structure then shows visually that this is a shared field rather than a custom one. Picking a predefined field is never compulsory. It is just usually the better choice. ##### The list of global fields These are the global fields available in every workspace. Use the system name in structures and integrations. ###### The person - `name_first` : first name - `name_last` : last name - `nickname` : nickname - `email` : email address - `phone_prefix` : international dialling prefix - `phone` : phone number without the prefix - `phone_full` : the whole number including the prefix - `birth_date` : date of birth - `age` : age - `gender` : gender - `nationality` : nationality - `language` : language - `marital_status` : marital status - `education` : level of education - `id_national_number` : national identification number - `id_card_number` : identity card number - `id_vehicle` : vehicle registration plate ###### Household - `household_members` : how many people live in the household - `household_children` : how many of them are children - `household_members_income` : the household’s combined income ###### Address - `address` : the whole address in one field - `address_street` : street - `address_street_number` : street number - `address_city` : city - `address_zip` : postal code - `address_state` : region - `address_country` : country ###### Contact address Use these when the contact address differs from the main one. - `address_contact_status` : a checkbox saying the contact address is different - `address_contact` : the whole contact address in one field - `address_contact_street` : street - `address_contact_street_number` : street number - `address_contact_city` : city - `address_contact_zip` : postal code - `address_contact_state` : region - `address_contact_country` : country ###### Company - `company_name` : company name - `company_registration` : registration number - `company_vat` : VAT number - `company_address` : the whole company address in one field - `company_street` : street - `company_street_number` : street number - `company_city` : city - `company_zip` : postal code - `company_state` : region - `company_country` : country - `company_invoicing_email` : invoicing email ###### Bank - `bank_account_number` : account number - `bank_account_code` : bank code - `bank_account_full` : the whole account in one field - `bank_iban` : IBAN - `bank_swift_bic` : SWIFT or BIC - `bank_name` : bank name - `bank_address` : bank address ###### Employment and income - `employ_type` : type of employment - `employ_position` : job position - `employ_time` : how long they have been employed - `employer_name` : employer name - `employer_address` : employer address - `fin_type` : type of income - `fin_income` : income - `fin_income_gross` : gross income - `fin_expenses` : expenses ###### The product - `amount` : amount of the product - `price` : price - `quantity` : quantity - `currency` : currency - `discount` : discount amount - `coupon` : coupon code - `purpose` : what the product or service is for - `period` : duration - `period_sub` : a second duration, when the product needs one - `period_unit` : the unit of the duration, such as day or month - `period_start` : start date - `period_end` : end date - `home_type` : housing classification ###### Items For products with more than one line, following the structure used by analytics platforms. - `item` : the list of items - `item_id` : item ID - `item_name` : item name - `item_brand` : brand - `item_variant` : variant - `item_category` through `item_category5` : up to five levels of category - `item_list_id` : list ID - `item_list_name` : list name ###### Assets - `asset` : the list of assets - `asset_type` : what kind of asset it is - `asset_status` : its status - `asset_variant` : its variant - `asset_value` : its value - `asset_unit` : the unit the value is in ###### Consents - `consent_processing` : consent with data processing - `consent_marketing` : consent with marketing ###### Other - `domains` : websites - `type` : a type of any kind - `status` : a status of any kind - `quality` : a quality of any kind - `consumption` : a consumption of any kind - `notes` : a free note ###### Missing something The list grows over time. If you keep building the same local field in every workspace, or an advertiser keeps asking for something that is not here, tell us. When it is common enough to be useful to others, we will add it as a global field, and everyone stops mapping it by hand. --- ## Field settings Field settings control how a field behaves in forms, APIs, and integrations. They define its technical identifier, display label, default behavior, and rules for visibility. ###### General Properties - **System name** – the internal identifier of the field. Used in integrations mapping. - **Type** – the field type (Text, Number, Checkbox, etc.). Determines what kind of data can be collected. See [Field types](https://paldock.com/knowledge-base/field-types/) for more information. - **Label** – the name shown to end users in forms. - **Placeholder** – helper text displayed inside the input when it is empty (e.g. “Enter your ZIP code”). - **Default value** – a pre-filled value that appears unless the user overwrites it. - **Input mode** – defines the expected input method in the frontend (e.g. text, tel, email). It mainly affects mobile devices, where it prompts the appropriate on-screen keyboard. See the section Input mode below for more information. - **Value format option** – an optional mask that formats the value in the frontend (e.g. ### ### ### for phone). This setting overrides the default mask defined by the field type. - **Example value** – a sample of what a correct value looks like. - **Note** – a description of the purpose or usage of the field. ###### Example value and Note are not internal Both appear in the API documentation your affiliate partners see for this offer. A partner reading that documentation sees the system name, the type, whether the field is required, the example value and the note. Write them for that reader. An example value of `1234567` on a company ID field, and a note explaining which register the number comes from, saves a support ticket. An empty example value means the partner guesses. ###### Conditional Display - **Not Show If System Name Equals** – hides this field if another field’s system name has the specified value. - **Show Only If System Name Equals** – displays this field only if another field’s system name matches the specified value. Both settings compare against one exact value. There is no “contains”, no “is not empty” and no way to combine two conditions on the same field. ###### Checkboxes Options that define the behavior of the field: - **Required field** – the field must be filled before submission. - **Editable** – the field can be modified by the user. - **Hidden field** – the field is stored but not shown in the form. ⚠️ Required is enforced in the form. A lead arriving through the [API](https://paldock.com/knowledge-base/api-integration/) is checked for its format only when the field is required, so a field left optional accepts whatever the caller sends. If a value has to be correct whatever the source, add a regex or a validation scenario. See [Field validation](https://paldock.com/knowledge-base/field-validation/). ###### Field-Type Specific Options Some field types add extra configuration sections: - **Checkbox Accordion** – includes a *Description* section to enter the explanatory text shown with the field. - **Select / Radio Button** – include a *Values* section to define the available options for selection. - **Slider** – includes **Min** and **Max** to set the range the user can choose from, and **Step** to set how much one move changes the value. Each entry in the Values section has two parts. The **value** is what gets stored on the lead and sent to an integration. The **label** is what the user reads on the form. When a lead is created over the API, the caller sends the value, not the label. ###### Input mode The **Input mode** setting defines the expected input method in the frontend. While it has little impact on desktop browsers, it is important on mobile devices, because it determines which type of keyboard will appear. Supported input modes: - **text** – default mode, shows the standard keyboard for free text. - **tel** – optimized for telephone numbers, shows a numeric keypad with 0–9, +, *, #. We usually recommend using this input mode even for phone numbers, as it provides a better keyboard layout. - **email** – optimized for email addresses, shows @ and . keys prominently. - **url** – optimized for URLs, shows /, ., and [www](http://www). shortcuts. - **numeric** – numeric keypad for entering numbers only (does not allow symbols like + or -). - **decimal** – numeric keypad with a decimal separator (“,” or “.” depending on locale). 👉 Tip: Always choose the input mode that best matches the expected content. This makes form filling faster and reduces input errors, especially on mobile. ###### Special use cases **Hidden field with default value** – You can hide a field from the user and set a default value in the field settings. This ensures that every record created with this structure contains the same constant value, even though the user never sees the field. Typical examples include internal flags, campaign IDs, or fixed country codes. **Hidden field filled by a scenario** – Instead of a static default, you can hide a field and let its value be filled automatically. Using [Modify](https://paldock.com/knowledge-base/modification/), the system can bring in values from an external service through [Connection Creator](https://paldock.com/knowledge-base/topics/connection-creator/). For example, you might provide a company ID in one visible field, and have the system automatically fill hidden fields such as company address, postal code, or operator. --- ## Field types Field types define what kind of data can be collected and processed in a specific field. Each field type has its own characteristics and use cases: ###### Text A free-form field that accepts letters, numbers, and special characters. It is most commonly used for names, addresses, or general inputs where no strict data type is required. ###### Number A numeric field that only accepts digits. It is used for quantities, amounts, ages, or any value that must be stored as a number. Text or special characters cannot be entered here, and if the number begins with a leading zero, that zero will be automatically removed. - You can set a **Min** and a **Max** in the field settings. Both are applied in the form. - Do not use Number for a value that only looks numeric, such as a postal code, a bank account or a national ID. Those need Text, because the leading zero matters. ###### Checkbox A binary field with two possible states: selected or not selected. It is typically used for consents, confirmations, or simple yes/no choices. - For this field type, validation does not apply, so it is hidden in the field settings. - The value of this field must be either **true** or **false** (when used in API) ###### Checkbox Accordion An extended version of the checkbox that allows additional descriptive text or expandable content. This is useful when a single choice requires explanation, such as terms of service or grouped agreements. - For this field type, validation does not apply, so it is hidden in the field settings. - When this field type is used, an additional Description section appears in the field settings. Here you can provide the content for this field. - The value of this field must be either **true** or **false** (when used in API) ###### Date A field for selecting calendar dates. It ensures that the input follows a valid date format and is commonly used for birthdays, contract dates, or scheduling information. ###### Select (Dropdown) A field that lets the user pick one value from a predefined list of options. It is suitable when the available answers are limited and should be standardized. - For this field type, validation does not apply, so it is hidden in the field settings. - When this field type is used, an additional Values section appears in the field settings. Here you can provide the list of values for this field ###### Multi-Select (Dropdown) A field that lets the user pick **multiple values** from a predefined list of options. Each selected value is displayed as a removable tag inside the field. It is suitable when users may need to choose more than one option from a standardized set. - For this field type, validation does not apply, so it is hidden in the field settings. - When this field type is used, an additional **Values** section appears in the field settings. Here you can provide the list of values for this field. ###### Radio Button A field where the user selects exactly one option from a predefined set. Unlike dropdowns, all choices are displayed on the form, making selection more visible and mobile-friendly. - For this field type, validation does not apply, so it is hidden in the field settings. - When this field type is used, an additional Values section appears in the field settings. Here you can provide the list of values for this field ###### Country A field where the user picks a country from the list maintained by PalDock. Use it instead of a Select with your own country list, so the same country is written the same way in every structure and every integration. - For this field type, validation does not apply, so it is hidden in the field settings. - The list of values is provided by PalDock, so no Values section appears in the field settings. ###### Phone A specialized field for entering phone numbers, including an international prefix. It ensures that the input is structured as a valid phone number rather than free text. - The prefix and the rest of the number are held separately. With global fields the prefix lands in `g_phone_prefix`, the number in `g_phone`, and the two joined together in `g_phone_full`. ###### Email A field intended for email addresses. It accepts inputs in email format only and is used for communication, user accounts, or identification. ###### Tag Input An interactive input where each entered value becomes a tag (chip). Users type a value, press Enter/Tab/Blur, and it’s converted into a separate tag. - **Stored value:** string[] – each tag is one array item. - **Best for:** values that may contain spaces, commas, or special characters. ###### List Input A textarea-based input where each line represents one value. Users can paste or type lists directly, e.g. copy from a spreadsheet. - **Stored value:** string[] – each line is one array item. - **Best for:** bulk operations and mass imports. ###### Delimited Input A single text field where multiple values are entered in one line and separated by a delimiter (comma, semicolon, pipe, etc.). - **Stored value:** string[] – the text is split into an array on submit, based on the chosen delimiter. - **Best for:** simple cases or when delimiter-based formats are explicitly required. ###### Slider A field where the user picks a number by dragging a handle along a track instead of typing it. Use it when the value is a rough amount rather than an exact one, such as a requested loan amount or a term in months, and when seeing the available range helps the user decide. - For this field type, validation does not apply, so it is hidden in the field settings. - When this field type is used, additional **Min**, **Max** and **Step** settings appear in the field settings. Min and Max set the range, Step sets how much one move changes the value. - The stored value is a number, so the user cannot submit anything outside the range you defined. --- ## Field validation Validation ensures that data collected in forms and structures is correct, usable, and consistent. It helps prevent invalid inputs from being stored in the system and allows you to enforce business rules on top of basic field constraints. Apart from the basic validation enforced by field type, you can use additional validation methods ranging from simple rules to advanced external services. ###### What validation applies to Two rules cover every case: - **Required** decides whether the field may be left empty. - **Everything else runs only on a field that has a value.** An empty optional field is not checked at all, so a regex or a validation scenario never turns an optional field into a required one. This is the same whether the lead comes from a form, an [embeddable form](https://paldock.com/knowledge-base/embeddable-form/), or the [API](https://paldock.com/knowledge-base/api-integration/). A partner sending leads over the API is held to the same rules as a visitor filling in the form. ###### Basic validation Some field types enforce a minimal level of validation: - **Number** – only digits are allowed, leading zeros are removed. - **Phone** – must be entered as a valid number with prefix. - **Email** – must contain a valid email pattern. - **Date** – must follow a valid date format. - **Checkbox** – must be `true` or `false`. - **Select** and **Radio Button** – must be one of the values defined on the field. These checks belong to the field type, so there is nothing to configure. See [Field types](https://paldock.com/knowledge-base/field-types/). ###### Regex validation You can configure regex validation rules to enforce custom patterns (e.g. a national identifier, a licence plate). You can describe the intended rule to AI to generate the regex, and then test it on multiple values using a tool such as [regex101.com](https://regex101.com/). A regex is the right tool when the rule is about the shape of the value and nothing else. If the rule needs to look the value up somewhere, use a validation scenario instead. ###### External validation through Connection Creator You can use the [Connection Creator](https://paldock.com/knowledge-base/topics/connection-creator/) to call an external service for validation. Typical examples include: - Checking whether a phone number or email actually exists. - Verifying a company ID against an official database. - Bank account to validate bank account numbers against banking standards. - Personal ID check to validate identifiers against checksum algorithms or national registries. - Domain check to validate that a domain exists, has active DNS records, or belongs to a specific organization. Many other validation scenarios can be implemented this way. ###### How a validation scenario works The scenario is built in the [Connection Creator](https://paldock.com/knowledge-base/connection-creator-in-structures/), where it calls the service and decides what the answer means. What it hands back to the field is one of two results: the value is accepted, or the value is rejected and the visitor is asked to correct it. Build a branch for every answer the service can give, including the one where it does not answer at all. ###### Handle the outage This is the branch people leave out, and it is the one that costs money. If the service is down and nothing in the scenario handles that, the field is never accepted and nobody can submit the form. An outage at the provider becomes an outage at your offer. Send that case to an accepted result instead. The value was not verified, but the lead is still collected. You lose one check for as long as the provider is down. Without it you lose every lead in that time. Decide this per field. A check that exists to keep data tidy should always fall back to accepted. A check that decides whether you may take the lead at all is the rare case where blocking is right, and even then you want to know how long you would be blocked for. ###### Validation can also record what it found A scenario can write a value into a field on its way through, so a check can both verify something and store the answer. An insolvency check can accept the lead either way and put `yes` or `no` into a field the advertiser receives. When you only want to store a value and never block anything, use [Modify](https://paldock.com/knowledge-base/modification/) instead. ###### More than one scenario on a field A field can have more than one validation scenario. **All of them must succeed for the value to be accepted.** One failure rejects the field, whatever the others returned. ###### The order things run in - Basic validation and regex run first, on every field that has a value. - Validation scenarios run only if that first pass found nothing wrong, anywhere in the form. So a value that fails its regex never reaches the external service. That saves a call, but it also means a scenario you are testing will not run at all while another field is still invalid. ###### What to watch out for ⚠️ Validation through an external service can break the entire system if it is set up incorrectly, preventing the form from being submitted and the lead from being created. Validation is always a trade-off between data quality and conversion rate. Stricter validation improves data accuracy, but it can also frustrate users filling out the form and cause them to abandon it before submission. - **Regex validation.** If a mask or regex validation fails, the user will be prompted to correct the input before submission. Always ensure that the validation rules are accurate so the form remains submittable. Prefer simpler expressions over overly complex ones, as complicated patterns can lead to unexpected behavior. - **Unhandled responses.** Write a branch for every answer the service can give, including the ones you do not expect. A response that matches no branch leaves the scenario with nowhere to go. - **Timeouts.** If an external service takes too long to respond, users are stuck waiting with a loading spinner until the request finishes. This creates a poor user experience and increases the risk of abandonment. Set the timeout on the HTTP node, and remember that the whole scenario runs while the visitor waits, so it has to finish inside the synchronous limit. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). 👉 Always balance validation strictness with usability. For mission-critical checks, use external validation, but configure fallbacks and reasonable timeouts to prevent the system from breaking. --- ## Modification A **Modify** scenario fills or changes the value of a field while the form is being filled in. Instead of relying only on what the user types, PalDock can write a value into a field based on other fields, or fetch it from an external service. Modify is a scenario attached to a field. It is not the same thing as the [Modify node](https://paldock.com/knowledge-base/modify-field-in-connection-creator/), which is one element inside a scenario. A Modify scenario often contains a Modify node, but it does not have to, and a Modify node can be used in any scenario, not only this one. The field being filled is usually hidden, but it does not have to be. This feature is especially useful when you want to: - Keep forms shorter and simpler for users, while still capturing all required data. - Add extra business context without manual input. ###### How Modify works A field can be set to fill automatically when another field is completed and the form is submitted. For example, entering a company ID may trigger an API call that fills in the company name, address, and postal code into their respective fields without the user needing to fill them up manually. This is done through [Connection Creator](https://paldock.com/knowledge-base/topics/connection-creator/), where you build the scenario and connect it to specific input and output fields. Examples include: - Looking up company details from a business registry. - Retrieving mobile carrier. - Completing address details based on ZIP code. - And many others. ###### More than one scenario on a field A field can have several Modify scenarios, and they run in the order you set. Use this when the value is built in steps, for example one scenario fetches the company record and a second one formats the address it returned. The order matters. A scenario that reads a value another scenario has not written yet will find the field empty. ###### Changing a value you already have Not every Modify needs an external service. When the value is already in the form and only needs reformatting, trimming, or combining with another field, use the Modify node’s operations instead of an HTTP request. That keeps the form fast, because nothing has to wait for a third party. See [List of modifications](https://paldock.com/knowledge-base/list-of-modifications/) for what the operations can do. ###### What to watch out for ⚠️ Modify through an external service can break the entire system if it is set up incorrectly, preventing the form from being processed and the lead from being sent to offer. - **External service outage.** If the service is unavailable, the form can be submitted, but cannot be processed until a valid response is received. To avoid this, configure a fallback response for the failure case, for example on status codes 4xx or 5xx, so the scenario finishes even when no value was filled. - **Timeouts.** If an external service takes too long to respond, users are stuck waiting with a loading spinner until the request finishes. This creates a poor user experience and increases the risk of abandonment. Set the timeout on the HTTP node, and keep in mind that the whole scenario runs while the visitor waits, so it has to finish inside the synchronous limit. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). - **Combination with validation.** If Modify from an external service fails, the field will not be populated. If validation is also enabled on that field, it will fail as well, preventing the form from being submitted. Both features must be configured correctly with this risk in mind. --- ## AutoComplete AutoComplete allows you to suggest values to the user while they are typing in a form field. Instead of filling in the full value manually, the system queries an external service and displays relevant suggestions (e.g. city names, street names, product codes). This feature improves the user experience by making forms faster to fill out and reducing input errors. ###### How AutoComplete works - The user starts typing into a field, for example City. - PalDock runs the scenario attached to that field, which calls an external service. See [Connection Creator in Structures](https://paldock.com/knowledge-base/connection-creator-in-structures/). - The service responds with a list of possible values. - The suggestions are displayed to the user as they type. - When the user picks one, the value is filled into the field. The user can still type a value that was not suggested. AutoComplete offers help, it does not restrict what the field accepts. If the value has to be one of a known set, use a [Select](https://paldock.com/knowledge-base/field-types/) field or add [validation](https://paldock.com/knowledge-base/field-validation/). ###### Setting it up Three things have to line up: - **The scenario** calls the service and passes in what the user has typed so far. - **The list of suggestions** is picked out of the response and stored under a name, for example `names`. - **The field** is linked to the scenario, and its accessor points at that name, so PalDock knows which part of the response holds the suggestions. If the accessor points at something that is not a list, no suggestions appear and nothing is reported. That is the first thing to check when a field stays silent. ###### Example: city names from OpenStreetMap The field in the structure has the system name `city`. The scenario sends a GET request to `https://nominatim.openstreetmap.org/search` with: - the value the user is typing, mapped to the `city` parameter - `featureType=city` - `format=json` - `limit=5` - a `User-Agent` header, which this particular service requires The response is a list of places. The scenario picks the name out of each one and stores the result as `names`. On the field, the accessor is set to `names`. Note the `limit=5`. A suggestion list is read at a glance, so a long one is worse than a short one, and every extra result costs response time the user is waiting through. ###### Typical use cases - Suggesting city or street names from geolocation services. - Offering product codes or SKUs from a product feed. - Completing company names from a business registry. - Providing postal codes based on partial input. ###### What to watch out for ⚠️ AutoComplete depends on external services. If the service is unavailable or slow to respond, suggestions do not load. - **Keep it fast.** The scenario runs while the user is mid-word, so the whole thing has to finish in a couple of seconds to be useful at all. Set a short timeout on the HTTP node. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). - **An outage is not a blocker here.** Unlike validation, a failed AutoComplete does not stop the form. The user sees no suggestions and types the value themselves. That is a good reason to use AutoComplete rather than a Select when the list is long and the service is not fully reliable. - **Watch the call volume.** The service is queried while the user types, not once on submit, so one filled form is several requests. Check what your provider allows and what it costs before you put AutoComplete on a high-traffic form. --- ## Translations Each field can be translated into multiple languages to provide a localized user experience. Translations apply to both the **Label (Name)** and the **Placeholder** of the field. - **Language** – choose the target language from the dropdown. - **Name** – the translated label that will be shown to the user. - **Placeholder** – the translated helper text displayed inside the input before it is filled. You can add multiple translations for the same field by clicking **Add**. Each translation can be managed individually, and existing translations can be removed if no longer needed. Additionally, translations can be imported or exported in bulk using the **Import** and **Export** buttons. This is especially useful when maintaining large forms or when collaborating with professional translators. The **language of the form** is controlled in the **Form Settings** and depends on the chosen form design. Once a language is set for the form, the corresponding translations for each field (Name and Placeholder) will be applied automatically. ###### What a translation does not change The form language only changes the **labels and placeholders** shown to the user. Everything else stays the same: - The **system name** of the field, which is what integrations map and what the API expects. - The **values** behind Select and Radio options. Only their labels can be translated, so an advertiser receives the same value whichever language the visitor saw. - **Validation**, **Modify** and **AutoComplete**, which run identically in every language. That last point is the one that catches people out. A phone regex written for one country’s format does not become a different regex because the form is shown in another language, and an address service that only covers one country still only covers that one. ###### When a translation is not enough If you need a form in a specific language with its own validation rules, its own scenarios, or different fields, create a separate [form structure](https://paldock.com/knowledge-base/form-structure/) instead of relying only on translations. A rough line to draw: - **Same fields, same rules, different words** is a translation. - **Different rules, different scenarios, or different fields** is a second structure. ###### A missing translation is not an error If a field has no translation for the language the form is set to, the original label and placeholder are shown instead. Nothing breaks and nothing is reported, so a partly translated form looks finished from the admin side and mixed to the visitor. Use the Export button to see which fields are still missing, rather than clicking through the form. --- ## Form structure A **Form Structure** defines which fields are collected when a lead is created. It acts as the blueprint for forms, API payloads, and partner integrations. - Ensures all leads follow a consistent format. - Defines which fields are required and optional. - Used in all forms generated by PalDock and in incoming API traffic. - Typical use cases: when each offer or product has its own specific field requirements. ###### One structure, three ways in A lead can reach PalDock through a hosted form, an [embeddable form](https://paldock.com/knowledge-base/embeddable-form/) on the affiliate’s site, or the [API](https://paldock.com/knowledge-base/api-integration/). All three are served by the same structure. A field you add appears in all of them at once, including in the API documentation your partners read. So does a field you make required, which is worth remembering when partners are already sending leads. ###### How it connects to offers and integrations - **A structure is attached to an offer**, and an offer can have more than one. Two landing pages that differ by a single field can share one offer instead of being duplicated. See [Multiple Structures for Offers and Integrations](https://paldock.com/knowledge-base/multiple-structures-for-offers-and-integrations/). - **An integration is built on exactly one structure.** Its fields are what you map into the advertiser’s request, so an integration can only send what its structure collects. If an advertiser needs a value that is not in the structure, add the field there first. Collecting it, hiding it, or filling it with [Modify](https://paldock.com/knowledge-base/modification/) are then all options. ###### Deciding how many you need One structure per offer is the normal case. Add another when the fields genuinely differ, not when only the wording differs. - **The same fields, different labels** is a job for [Translations](https://paldock.com/knowledge-base/translations/) or for editing the label, not a second structure. - **The same fields, different rules or scenarios** does need a second structure, because validation and Modify are set per field. - **Different fields** obviously needs a second structure. Every extra structure is another place to maintain when an advertiser changes what they want, so the cost is real but it is paid later. 👉 For details about field types, validation, Modify, and translations, see the other pages in this section. --- ## User structure A **User Structure** defines the fields collected when users register or manage their account in PalDock. Separate structures exist for **Affiliate partners** and **Advertisers**. - Used in registration forms and user management. - Can include global fields (Name, Email) as well as any custom fields. - Admins can customize fields to fit their tenant’s needs. ###### It is not attached to anything Unlike a [form structure](https://paldock.com/knowledge-base/form-structure/), a user structure is not connected to an offer or an integration. The registration form and the account page use it directly, so a change takes effect the moment you save it, for people who registered long ago as well as for new ones. ###### Some fields belong to the person, not to you Global fields such as first name, last name and email are tied to the user’s [account](https://paldock.com/knowledge-base/one-account-multiple-workspaces/), which spans every workspace they have access to. - When the user changes one of these, it changes in every workspace at once. - An admin cannot change them on the user’s behalf. That is deliberate. The same person should not be called two different things in two workspaces. If you need a value that behaves differently, make a local field instead, and accept that it will not be linked to the account. See [Local, Global and Custom fields](https://paldock.com/knowledge-base/local-versus-global-fields/). ###### What to collect A registration form is where partners decide whether to bother. Every field you add is a reason to stop. - Ask for what you need to pay them and to know who they are. - Anything you only need later, such as billing details or a tax number, can be collected when it becomes relevant rather than at sign-up. - [Validation](https://paldock.com/knowledge-base/field-validation/), [Modify](https://paldock.com/knowledge-base/modification/) and [AutoComplete](https://paldock.com/knowledge-base/autocomplete/) work here exactly as they do in a lead form, so a company number can be checked against a registry during registration. 👉 For details about field types, validation, Modify, and translations, see the other pages in this section. --- ## Feed structure A **Feed Structure** defines the format of product feeds imported into PalDock. Feeds contain product details (such as name, price, availability) and can be used by affiliates or in lead distribution logic. - Used for importing data from external sources (CSV, XML, API). - Fields can be mapped and extended with calculations or transformations. - Powers product display for affiliates and supports logic in pingtrees and FinalPages. ###### It describes rows, not a submission This is the one structure where nobody is filling anything in. A [form structure](https://paldock.com/knowledge-base/form-structure/) describes one lead created by one person. A feed structure describes the shape of every row in an imported file, and the same structure is applied to all of them. That changes what the advanced options are for: - **[Modify](https://paldock.com/knowledge-base/modification/)** is the one you will use most. Prices arrive in the wrong currency, names arrive with the brand attached, availability arrives as `1` and `0`. Modify normalises them on the way in. - **[Validation](https://paldock.com/knowledge-base/field-validation/)** decides what happens to a row that does not fit, rather than what a visitor is told to correct. - **[AutoComplete](https://paldock.com/knowledge-base/autocomplete/)** has nothing to suggest to, so it does not apply here. ###### Nothing is waiting for it A feed runs in the background on its own schedule, not while somebody watches a loading screen. The synchronous limit does not apply, so a feed scenario can take far longer than a form scenario and can call a slow service without costing you a conversion. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). 👉 For details about field types, validation, Modify, and translations, see the other pages in this section. --- ## Multiple Structures for Offers and Integrations An [Offer](https://paldock.com/knowledge-base/topics/offers/) can have more than one [structure](https://paldock.com/knowledge-base/topics/structures/). You do not need a separate offer, or a separate integration, for every form. ###### Why this exists You often have several structures that are almost the same. Two products, two landing pages, and the only difference is a single field. Copying the whole structure, and then maintaining both copies with all their modifications, is slow and easy to get wrong. For when a second structure is the right answer and when it is not, see [Form structure](https://paldock.com/knowledge-base/form-structure/). ###### How structures reach an integration Structures are attached to the **offer**. Integrations are added to the offer through its [pingtree](https://paldock.com/knowledge-base/distribution/). So an integration works with whatever structures its offer has, without being linked to them itself. When you map fields in that integration, you see the fields from all of the offer’s structures, deduplicated by name. You map each one once and it works for every structure. ###### Matching is by name only PalDock matches fields by **system name**. A lead always arrives from exactly one structure. When the integration builds its request, it looks up a field by its system name and takes whatever value that lead carried. It never asks which structure the lead came from. The field type plays no part in this. An integration does not see whether a field is text, a number or a dropdown, and cannot work with that information. It only sees the name and the value. This also means two structures can define the same system name with different field types and the integration will not notice. It takes the value it finds. Whether that is a problem depends on what the advertiser does with it. ###### What you need to keep true This works only while the names stay consistent. Two rules: - The same meaning must have the same system name in every structure on the offer. If one calls it `phone` and another `phone_number`, the integration sees two different fields and one of them will always be empty. - The same system name must always mean the same thing. If `id` is a customer number in one structure and a product code in another, the integration will send the wrong value and nothing will warn you. Use [global fields](https://paldock.com/knowledge-base/local-versus-global-fields/) wherever you can. Their system names are managed centrally, which is exactly what this depends on. Use local or custom fields only for what genuinely differs. ###### When a field is missing from one structure Structures on the same offer are rarely identical, so a mapped field will sometimes have no value. By default it is sent empty. The advertiser receives the key with nothing in it. That is often not what you want, so decide what should happen before you go live: - Leave the field out of the request entirely with [do-not-send](https://paldock.com/knowledge-base/do-not-send/). - Fill it with a default value using [Modify](https://paldock.com/knowledge-base/modify-field-in-connection-creator/). - Send it empty, if the advertiser accepts that. ###### Example Two landing pages sell the same insurance. Structure A asks for a company ID, Structure B does not. Everything else is identical. Put both structures on the same offer and add the integration to its pingtree. Map the shared fields once. For the company ID, use Modify to decide what happens when it is empty. One offer, one integration, two forms, nothing duplicated. --- # Connection Creator ## About connection creator **Connection Creator is a visual builder.** You place nodes on a canvas and connect them with arrows. Together they form a scenario = a flow that runs whenever something happens in PalDock. ###### Nodes and connections - **Node** = one action. Send an HTTP request, set a variable, modify a field, wait, finish. - **Connection** = an arrow between two nodes. It decides what runs next. Arrows can carry conditions. ###### Scenario and run - **Scenario** is the flow you build and save. - **Run** is one execution of it. Every lead, postback or form submit starts its own run. Runs are logged separately, so you can always see what happened to one specific lead. ###### Types of scenarios A scenario always belongs to one context. The context decides what triggers it and what data it receives. - **Integration**: sends a lead to an advertiser and processes the answer. - **Structure: ** **validation**: checks a value while the form is being filled in, and can block the submit. - **modification**: fills a field with a value from an external service (Autofill). - **autocomplete**: suggests values to the visitor while typing. - **Tracking**: **S2S postback (incoming**): processes a conversion or status update sent to PalDock. - **Tracking API (outgoing)**: sends conversion and status data from PalDock to affiliates or other systems, and can also poll an advertiser for a result. - **Feed**: pulls product or offer data from an external source. ###### How data moves The first node receives the incoming data – such as form fields, tracking parameters, system tags and others. Each node then reads that data, does its job, and writes its own values back. Everything travels forward. A node can use any value produced by any node before it. Nothing is passed backwards. ###### Order Nodes run one after another, following the arrows. - If a node has several outgoing arrows, every arrow whose condition is met is followed. Arrows are evaluated in the order they are listed on the node, so if two of them can both apply, the one higher in the list runs first. - If a condition is not met, that arrow is skipped. - A branch can end on its own without stopping the other branches. ###### Immediate or background Some scenarios must return an answer while the visitor is waiting such as form validation, autocomplete or a lead sent over the API. These run immediately and the caller waits for the result. Others run in the background such as outgoing Tracking API. They are queued and processed without blocking anything. ###### Pausing A **Wait** node pauses the run for a set time. A **Webhook** node pauses it until an external system calls back. The run stays open, keeps its data, and continues from the same place. ###### Errors and limits - A node runs **once**, with no automatic retry. Every part of the flow also has a time limit, and a scenario that runs while a visitor waits has the tightest one of all. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). - Failures are counted and written to the run log. Use response conditions to decide what should happen next instead of relying on the failure itself. - A **Breaker** node limits how many times a loop may repeat, so a flow can never run forever. - A scenario can start another scenario, but a scenario cannot call itself in a circle. ###### Where to look when something breaks Every run stores the input and output of each node. Open the run and follow it node by node and you will see the exact data each node received and returned. --- ## Where Connection Creator is used Connection Creator is not a separate tool. It is the engine behind every place in PalDock that talks to an outside system. A scenario always belongs to one of four contexts, and the context decides what starts it, what data it receives, and whether anyone is waiting for the answer. ###### Integration Sends a lead to an advertiser and processes the answer. Started when a lead reaches an offer, either directly or through a pingtree. The scenario receives the lead data and gives back the result: accepted or rejected, the redirect URL, the advertiser’s own ID for the lead. See more [here](https://paldock.com/knowledge-base/connection-creator-in-integration/). This is the most common use, and it is the one the [Integration Library](https://paldock.com/knowledge-base/library-of-integrations/) is built for. ###### Structure Runs inside the form itself, while the lead is still being created. See more [here](https://paldock.com/knowledge-base/connection-creator-in-structures/). Three purposes: - **Validation** checks a value while the form is being filled in and can block the submit. - **Modification** fills a field with a value from an external service. See [Modification](https://paldock.com/knowledge-base/modification/). - **Autocomplete** suggests values to the visitor while typing. See [AutoComplete](https://paldock.com/knowledge-base/autocomplete/). All three run while the visitor is waiting, so they must be fast. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ###### Tracking Handles conversion and status data moving in and out of PalDock. Two directions: - **Incoming postback** processes a conversion or status update sent to PalDock. - **Outgoing postback** sends conversion and status data from PalDock to affiliates or other systems, and can also poll an advertiser for a result. Both run in the background. Nothing is waiting for them, so they can take longer and can pause and resume. See more [here](https://paldock.com/knowledge-base/connection-creator-in-tracking/). ###### Feed Pulls product or offer data from an external source and brings it into PalDock. Runs in the background on its own schedule. ###### Where scenarios live All scenarios are managed in the Tools menu, in the respective section based on the context they belong to. To add one, click **Add** and choose either a custom integration or a prebuilt one from the [Library of Integrations](https://paldock.com/knowledge-base/library-of-integrations/). If you use [global fields](https://paldock.com/knowledge-base/local-versus-global-fields/), most library integrations are ready after a single click. ###### How scenarios are triggered The context decides what starts a scenario: - **Integration** starts when a lead is sent to an offer, either directly or through a [pingtree](https://paldock.com/knowledge-base/distribution/). - **Structure** starts while data is being entered: a lead in a [form](https://paldock.com/knowledge-base/form-structure/), a partner during [onboarding](https://paldock.com/knowledge-base/user-structure/), or a record during [feed](https://paldock.com/knowledge-base/feed-structure/) ingestion. - **Incoming postback** starts when PalDock receives a call from an external system. - **Outgoing postback** starts when something happens inside PalDock, for example a new conversion or a status change. - **Feed** starts on its own schedule. --- ## Editor The Editor is the visual tool where you build a scenario. Nodes appear as dots on a canvas. You drag them, connect them with lines, and configure what each one does. ###### Nodes A node is one action: send a request, change a value, wait, finish. There are two kinds. - **Built-in nodes** are the core elements provided by PalDock, such as Start, Modify or HTTP. They work the same in every workspace. - **External nodes** represent an outside service or API and are what connects PalDock to a third-party platform. Click any node to open its configuration panel, where you define its inputs, outputs and rules. ###### Adding a node Click the plus on the canvas and a panel opens with everything you can add. Type in the search box to find a node by name, or browse the groups: - **Flow control** decides when and whether things happen: Wait, Breaker. - **Data operations** change the data: Modify, Set. - **Connections** talk to the outside world: HTTP, Webhook. - **Composition** builds the scenario itself: Start, End, SubScenario, Mirror. The tabs along the top are only a filter. The first one shows the nodes you reach for most often, and the rest narrow the list to one group. Nothing is hidden, so if you know the name, searching is quicker than browsing. See [List of nodes](https://paldock.com/knowledge-base/list-of-nodes/) for what each one does. ###### The Start node Every scenario begins with a Start node. Its type follows the context the scenario belongs to: Integration, Structure or Tracking. See [Where Connection Creator is used](https://paldock.com/knowledge-base/where-connection-creator-is-used/). A scenario can have more than one Start node when it serves separate paths that must not touch, which is how PING and POST flows are built in a pingtree. See [How to integrate anything](https://paldock.com/knowledge-base/how-to-integrate-anything/). ###### Connecting nodes Nodes are joined by lines. A connection defines the order in which nodes run. Connections can branch. One node can lead to several others, so the flow takes a different path depending on a condition, for example routing leads to different integrations based on a validation result. Every connection can carry a condition that decides whether the flow continues along it. If the condition is not met, that line is not followed, while other lines from the same node still can be. See [Connections with Conditions](https://paldock.com/knowledge-base/connections-with-conditions/). ###### Choosing a value Almost every node asks you for a value: which field to send, what to compare against, where to store a result. You never have to remember names. Open the picker and take what you need from what the scenario has at that point. It offers four groups: - **Form fields** are the fields of the structure the lead came from, such as `first_name` or `email`. They are grouped the way the structure is, so related fields sit together. - **Keys** are the tokens, endpoints and parameters this integration uses. - **System parameters** are the values PalDock fills in itself, covering the conversion, the commission, the offer, the advertiser, the affiliate, the integration and the time. - **Previous steps** is everything the earlier nodes produced, including a path into a response body. The picked value appears as a tag in the field, and underneath it is stored in braces, such as `{email}` or `{external_id}`. You can type instead of picking, and mix the two freely, so `Bearer {token}` works as one value. Only what was produced before the current node is available, because data travels forward and never back. If you need a value of your own, store it with a [Set](https://paldock.com/knowledge-base/set/) node and reference it by name afterwards. See page [parameters ](https://paldock.com/knowledge-base/parameters/)for what PalDock provides. ###### Turning a node off A node can be disabled without deleting it. A disabled node is skipped and the flow does not continue past it. This is the safe way to take one branch out of a live scenario while you work on it. ###### Reusing a node If the same request or configuration is needed in several places, do not copy it. Use a [Mirror](https://paldock.com/knowledge-base/mirror/) node, which inherits all settings from its master and updates automatically whenever the master changes. ###### Typical workflow - **Start.** Every scenario begins with a Start node. - **Add nodes.** Drag in built-in actions or external integrations. - **Connect.** Join them to define the order, and add conditions where the flow should branch. - **Configure.** Open each node and set its parameters, such as endpoints, credentials, field mapping and rules. - **Run and test.** Execute the scenario and check what happened in the log. ###### Checking what happened Every run stores the input and output of each node. Open the run and follow it node by node. You will see the exact data each node received and returned, which is where you start whenever something does not work. See [Logs](https://paldock.com/knowledge-base/logs/). --- ## How to integrate anything This page is the practical route from an advertiser’s API documentation to a working integration. [The Editor](https://paldock.com/knowledge-base/editor/) explains the tool. This explains the method. ###### Before you start Have these ready: - The endpoint and the HTTP method. - How the request authenticates: a token, a header, a signature. - Which fields are required, and in what format. - Check whether the advertiser restricts access by IP address. If so, provide them with the PalDock outgoing IP address below. However, we highly discourage relying on IP whitelisting, as it is an outdated approach that tends to cause more problems than benefits. 159.69.100.31 - 159.69.101.229 - What a successful response looks like, and what a rejection looks like. - Test credentials, so you can send real requests without creating real leads. If any of these are missing, get them first. Most integrations that take a long time to build are missing one of them. ###### 1. Create the integration Integrations live in the **Integrations** section. Click **Add** and either start from scratch or pick a ready-made one from the [Library of Integrations](https://paldock.com/knowledge-base/library-of-integrations/). If the advertiser is already in the library and you use [global fields](https://paldock.com/knowledge-base/local-versus-global-fields/), you may be finished in one click. ###### 2. Add the Start node Every scenario begins with a Start node. Choose the type that matches what the scenario is for: Integration, Structure or Tracking. See [Where Connection Creator is used](https://paldock.com/knowledge-base/where-connection-creator-is-used/). ###### 3. Put the data into the right shape Advertisers rarely accept your data as it is. Phone numbers need a prefix stripped, dates need a different format, a country needs to become a code. Use a [Modify](https://paldock.com/knowledge-base/modify-field-in-connection-creator/) node for this, not the HTTP node. Keeping the transformation separate makes it obvious later where a wrong value came from. ###### 4. Send the request Add an [HTTP](https://paldock.com/knowledge-base/topics/connection-creator/element-types/http-node/) node and fill in the method, the URL, the headers and the body. Values from the lead go in curly braces, for example `{email}`. Two settings on this node matter: - **[Timeout](https://paldock.com/knowledge-base/limits-and-timeouts/)**, how long to wait for the answer. If a visitor is waiting on a loading screen, keep it low. - **[Signature](https://paldock.com/knowledge-base/signature/)**, if the advertiser requires the request to be signed. For nested payloads, see [Field format](https://paldock.com/knowledge-base/field-format/). ###### 5. Read the response An answer of `200 OK` does not mean the lead was accepted. Most advertisers return a rejection inside the body with a perfectly normal status code, so read the body, not just the code. Store what you need with a [Set](https://paldock.com/knowledge-base/set/) node. The values worth storing almost every time: - The advertiser’s own ID for the lead, into `{external_id}`. Without it you cannot match a later postback to this lead. - The redirect URL, into `{redirect_url}`, if the visitor is sent onwards. - The price, if the advertiser returns one. ###### 6. Decide what counts as success Put a condition on the connection leaving the HTTP node, so only an accepted lead continues down the success path. Everything else goes down the other path. Be specific about what success means. Matching on a status code alone is the most common reason an integration reports accepted leads that the advertiser never received. ###### 7. Finish the flow End the flow so PalDock knows the outcome. A rejection is a valid outcome, not an error, and it belongs in the reporting the same as an acceptance. See [Reject reason](https://paldock.com/knowledge-base/reject-reason/) and [Refuse leads](https://paldock.com/knowledge-base/refuse-leads/). ###### PING and POST in a pingtree When an integration is used in a [pingtree](https://paldock.com/knowledge-base/distribution/), it can have more than one Start node, because each flow has its own separate path. - The PING flow has its own Start and its own End. - The POST flow has its own Start and its own End. - Never connect PING and POST directly. The two flows must stay separate, with no connection between them. ###### Waiting, repeating and verifying Some advertisers do not answer immediately. - Add a **[Wait](https://paldock.com/knowledge-base/wait-node/)** node to pause before you ask again. Remember that the visitor stays on the loading screen while this happens, so watch the [synchronous limit](https://paldock.com/knowledge-base/limits-and-timeouts/). - There is no node that retries on its own. You build the loop: an HTTP node asks for the status, and a connection leads back to the Wait for as long as the answer is not final. - Always put a **[Breaker](https://paldock.com/knowledge-base/breaker-node/)** in that loop. It caps how many times the flow may go round, so a lead the advertiser never decides on ends cleanly instead of failing on a system limit. - If the lead has to be verified, that is usually a second HTTP request after the first one succeeds. If the advertiser calls you back instead of answering, use a [Webhook](https://paldock.com/knowledge-base/webhook-node/) node, which can wait far longer because nothing is blocked while it does. ###### Saving values from responses You can store a value returned by a request and use it later in the flow, or after it. - Predefined variables are listed in [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). - For your own variable, save it to a parameter with the prefix `custom_` and reference it as `{custom_anything}`. Stored values are kept in the database, so they remain available to tracking and postbacks long after the run has finished. ###### Test it before you go live Send a test lead and open the run in the log. Go node by node and check what each one received and returned. Test a rejection too, not only an acceptance, because that is the path that usually breaks silently. ###### Common mistakes - Treating `200 OK` as acceptance. - Not storing `{external_id}`, so postbacks cannot be matched later. - Not storing `{redirect_url}`, so customers cannot be redirected to advertiser. - Connecting PING and POST. - A timeout so long that the visitor gives up before the flow finishes. --- ## Connection Creator in Integration An integration scenario sends a lead to an advertiser and processes the answer. It starts when a lead reaches an offer, either directly or through a [pingtree](https://paldock.com/knowledge-base/distribution/). Everything else on this page is a variation on the same three steps: put the data in the shape the advertiser wants, send it, and read the answer. ###### One integration is one advertiser and one channel An integration covers a single advertiser through a single channel. That matters because the same advertiser usually appears in your pingtree more than once, and each of those channels is its own integration. They are duplicates. The scenario, the nodes and the mapping are identical, and the only thing that differs is a value: a different token, and with it a different price for the lead. Buying at one price is one channel, buying at another is a second channel with a second token. So build the integration once, get it working, then duplicate it per channel and change the credentials. Do not rebuild the logic each time, because then a fix has to be made in several places and eventually will not be. **In an auction, the integration must return `{price}`.** The pingtree needs it to compare bids and decide who wins. Without it, the integration cannot take part in an auction at all. Store it from the ping response the same way you store anything else. ###### The two flows A Start node has a flow. In integrations there are two, and each is a separate path with its own Start and its own End. - **Ping** asks whether the advertiser wants the lead, and at what price. Nothing is created on their side. - **Post** actually submits the lead. Never connect them. They are two flows on one canvas, not two halves of one flow. Not every advertiser needs both. If they only accept submissions, build the Post flow and leave it at that. If they support a pre-check, the ping usually calls a lighter endpoint and only needs to answer one question: yes or no. Some advertisers add a third step, where the lead has to be confirmed by a code sent to the customer. That gets its own Start node too. See Verification below. ###### What the scenario has to give back Sending the lead is half the job. The answer has to be stored, or the lead is delivered and then lost. Two values matter almost every time: - **`{external_id}`**, the advertiser’s own ID for the lead. Without it you cannot match a later postback, so the conversion never gets confirmed. - **`{redirect_url}`**, where the customer goes next, if the advertiser hands back a link. Store them with a [Set](https://paldock.com/knowledge-base/set/) node placed after the HTTP node, reading straight from the response, for example `{external_id}` = `{parsedBody.leadId}`. ###### The simplest integration One flow, four nodes: - **Start**, flow Post. - **[Modify](https://paldock.com/knowledge-base/modify-field-in-connection-creator/)** to put the data in the advertiser’s shape. - **[HTTP](https://paldock.com/knowledge-base/http-node/)**, a POST with the lead in the body. - **Set** to store the response, then **End**, success. The condition sits on the connection leaving the HTTP node. It is what decides whether the lead was accepted, so make it specific: ``` `{status} equals 201 {parsedBody.status.message} contains Created` ``` All conditions on one connection must be true for it to be followed. Checking the status code alone is the single most common reason an integration reports accepted leads the advertiser never received. ###### Preparing the data The Modify Field node before the request does the unglamorous work. Four things come up constantly. **Translating values.** Your form stores `full-time`, the advertiser expects `employed`, or `1`, or `EMPLOYMENT`. One Modify Field node holds all of these mappings, one section per field. This is why the node exists: keep the translation in one visible place instead of burying it in the request body. **Capping values.** The advertiser accepts loans up to a maximum, and your form allows more. Replace anything above the limit with the limit, rather than sending a value that will be rejected. **Filling required fields that are empty.** Some advertisers reject a request outright when a field is missing, even when the field is irrelevant. Replace the empty value with a placeholder. **Reformatting.** Adding an international prefix to a phone number, changing a date format, splitting or joining values. ###### Authentication Three patterns cover almost everything. **A static token** goes straight in a header or a query parameter as `{token}`. Nothing to build. **Basic auth** needs the credentials joined and encoded first. A Set node builds the string, then a Modify Field node applies `to-base64`, and the result goes into the header as `Basic {auth}`. **A token you have to fetch** needs its own request before the real one. The Post flow starts with an HTTP node calling the auth endpoint, a Set node stores `{token}` from the response, and only then does the flow continue to the actual submission. Put a condition on the connection so the flow only continues when a token actually came back. If the advertiser requires signed requests, use the [Signature](https://paldock.com/knowledge-base/signature/) setting on the HTTP node rather than building the signature yourself. ###### When the advertiser does not answer immediately Plenty of advertisers accept the lead, then take a few seconds to decide anything useful. There are two ways to handle it. **Poll them.** Add a **[Wait](https://paldock.com/knowledge-base/wait-node/)** node, then an HTTP node that asks for the status, then conditions on the outgoing connections: - A final positive state continues to the Set node and the End. - A final negative state goes to an End marked failed. - Anything else loops back through a **[Breaker](https://paldock.com/knowledge-base/breaker-node/)** and another Wait. The Breaker caps the number of attempts, so the flow cannot poll forever. Match the “still waiting” branch with *does not match* against the known final states, so a state you have never seen lands in the retry loop instead of falling through. **Let them call you.** If the advertiser sends a callback, use a [Webhook](https://paldock.com/knowledge-base/webhook-node/) node. The flow pauses there and continues when the call arrives, which is cheaper than polling and usually faster. A webhook can deliver several kinds of event, so branch on what arrived. Conditions on the connections leaving the node read the values from the callback, and each kind of event goes its own way. Give the webhook its own retry path as well, through a Wait and a Breaker, so a callback that never comes does not leave the flow hanging until the timeout. Remember that the customer is often sitting on a loading screen while all of this happens. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ###### More than one request Some advertisers need a sequence: submit the lead, ask for the offer, accept the offer, then ask again to confirm it was accepted. Each of those is another HTTP node, chained with conditions between them. Two things keep this manageable: - Store the ID from the first response into `{external_id}` immediately, because every later request needs it in the URL. - Give each step its own condition. If you only check the last response, you will not know which step actually failed. Once the sequence is more than three requests long, it is worth asking the advertiser whether there is a simpler endpoint. Often there is. ###### Verification Some advertisers confirm the lead with a code sent to the customer by SMS. This runs as its own flow with its own Start node. The pattern is: - In the Post flow, store whatever identifies the pending verification, for example the token ID and the token code returned by the advertiser. - In the verification flow, send those back together with the code the customer typed, available as `{code}`. - On success, store `{redirect_url}` and end. The two flows are connected by the values stored in the first one, not by a line on the canvas. ###### Ending the flow Every path should reach an End node, and the End node decides how the lead is recorded. - **Success** means the advertiser took the lead. - **Failed** means they did not. A rejection is a normal outcome, not an error. Give it a reason so it shows up usefully in reporting, rather than landing in Error along with genuine breakages. See [Reject reason](https://paldock.com/knowledge-base/reject-reason/). ###### Common mistakes - Treating any 2xx status as acceptance. - Not storing `{external_id}`, so postbacks can never be matched. - Not storing `{price}` in an integration meant for an auction, so it cannot bid. - Rebuilding the logic for each channel instead of duplicating the integration and changing the credentials. - Translating values inside the HTTP body instead of in Modify Field, which makes a wrong value impossible to trace. - Connecting the Ping and Post flows. - A polling loop with no Breaker. - Leaving a branch without an End node, so the lead ends up in neither result. --- ## Connection Creator in Structures A Structure scenario runs **inside the lead flow itself**, while the customer is still filling in the form. It can shape the data, fill in what is missing, or stop the lead before it is finalised. You find these under **Tools / Validation**. There are three purposes. All three are built the same way, with an HTTP node to call the external service, a Set node to store the result, and conditions on the connections to branch on the response. What differs is how they end. - **Validation** checks a value against an external service and can reject the lead. - **Modify** fills a field with a value pulled from somewhere else. - **Autosuggest** offers suggestions while the customer types. ##### The customer is waiting Structure scenarios always run instantly. The customer is sitting in front of the form while the flow executes, so the whole thing has to finish inside the synchronous limit, not just one node. Keep the HTTP timeout short and do not chain lookups you do not need. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ##### What decides whether the lead is rejected Not the response. Not the branch. The **success setting on the End node**. An End node set to *failed* rejects the lead. An End node set to *success* lets it through, whatever the branch was about. The title of an End node has no effect. You can call it Invalid and still let the lead through, and that is exactly what a Modify scenario does: finding no company number is a valid outcome, it just means the field stays empty. Read the success setting, not the label. Two rules: - Only the branch that genuinely means “this value is wrong” should end in *failed*. - An outage or an unexpected response must never end in *failed*. Otherwise every hiccup on the other side starts rejecting real customers. #### Validation Ask an external service whether a value the customer entered is valid, and reject the lead if it is not. Phone numbers are the usual case, since bad numbers are the biggest single source of rejected leads. The shape: - **Start** node, type Structure. - **HTTP** node, usually a GET, sending the field value to the validation endpoint, for example `phone={phone}`. - **Three connections out of the HTTP node**, each with its own condition: **Valid.** `{status}` equals `200` **and** `{parsedBody.valid}` equals `true`. Ends in *success*. - **Invalid.** `{parsedBody.valid}` equals `false`. Ends in **failed**. This is the only branch that rejects. - **Outage.** `{status}` matches `\b[45]\d{2}\b`. Ends in *success*, because a broken service is not a bad lead. All conditions on one connection must be true for it to be followed. That is why the valid branch checks two things: that the call succeeded **and** that the service said yes. Checking only the body means an error response with no `valid` field can slip through. Match the outage branch with a pattern rather than listing individual status codes. Anything unexpected then lands there instead of falling through somewhere it should not. #### Modify Take something the customer already gave you, look it up externally, and fill a different field with the answer. A company registration number becomes a company name and address. The shape is the same as validation, with one difference: **every branch ends in success**. Enrichment must not reject a lead just because the lookup came back empty. An empty result is an answer, not a failure. Use *failed* only when a missing value is by itself a genuine reason to turn the lead away. The shape: - **Start** node, type Structure. - **HTTP** node calling the lookup endpoint, for example `companyNumber={company_number}`. - **Three connections:** **Found.** `{status}` equals `200` and `{parsedBody.name}` is not empty. A Set node writes `{company_name}` = `{parsedBody.name}`, then End, *success*. - **Not found.** `{status}` equals `200` and `{parsedBody.name}` is empty. A Set node with nothing in it, so the field stays blank, then End, *success*. - **Outage.** The 4xx or 5xx pattern. End, *success*. Handle both real outcomes explicitly. Do not leave the negative case to a fallback, because then you cannot tell “we looked and found nothing” apart from “we never got an answer”. ##### When the API needs something the customer did not give you Sometimes the lookup needs an input that is not a field on the form. The form collects a full name in one field, and the registry expects a first name and a last name separately. Add a **[Modify Field](https://paldock.com/knowledge-base/modify-field-in-connection-creator/)** node **before** the HTTP node. It reads the field you have, transforms it, and writes the result into new fields the request can use. If you then add a guard on the imported field, such as a `do-not-send`, be careful with the condition. It has to compare against the live value from the response, written in braces as `{parsedBody.name}`. Typed without braces it is just a literal string, it can never match, and the guard silently does nothing. #### Autosuggest While the customer types, call a suggestion service and hand back a list for the form to show as a dropdown. This is the simplest of the three. No branching, no rejection: - **Start** node, type Structure. - **HTTP** node, usually a POST, sending the partial input, for example `fieldType: COMPANY_NAME` and `values.COMPANY_NAME: {company_name}`. - **Set** node storing the whole list, for example `{autocomplete_result}` = `{parsedBody.suggestions}`. - **End** node, *success*. The form takes it from there: it renders the list and lets the customer pick one. Because this runs on every keystroke, the timeout matters more here than anywhere else. A slow suggestion service does not just delay the answer, it makes the field feel broken. --- ## Connection Creator in Tracking Connection Creator is not only for delivering leads. It also handles what happens to a conversion **after** the lead was delivered: confirming it, updating it, or deciding what it is worth. There are two directions, and the difference is who makes the call. - **[S2S postback](https://paldock.com/knowledge-base/tracking-s2s-postback/)** : the advertiser calls PalDock. - **[Tracking API](https://paldock.com/knowledge-base/tracking-api/)** : PalDock calls out. Both use the same editor. This page is about what you build inside it. When each one fires, and how an incoming S2S postback is matched to a lead, is covered on those two pages. #### S2S postback The scenario runs when an advertiser reports the outcome of a conversion: approved or rejected, the sale value, the approved loan amount. **The simple case needs no scenario at all.** The postback is received and stored on its own. You only build a flow when something more has to happen. **The useful case** is branching on what arrived. Send another request when the postback comes in incomplete, or work out the commission from a value the advertiser reported. One thing to set up first: if a postback has any steps configured, the advertiser must send a **Postback ID** with the call. Without it the postback is still received, but your flow never runs. ##### Example: commission tiers based on the loan amount The advertiser sends `{value}`, the approved principal. The scenario reads it and sets `{commission}`: - `{value}` under 500 : commission 10 USD - `{value}` from 500 to 800 : commission 17 USD - `{value}` 800 and above : commission 23 USD In the editor: - One **Start** node - Several connections leaving it, each with a condition comparing `{value}` against a threshold, using *is less than*, *is greater than or equals* and so on. See [Connections with Conditions](https://paldock.com/knowledge-base/connections-with-conditions/). - One **Set** node per branch, writing the amount into `{commission}`. The pattern to remember: conditions live on the connections leaving the Start node, and every branch ends in a Set node that writes the final value. ##### Building on top of it Once `{commission}` is set, you can reference it in a commission formula, for example `{commission}+10` for a VIP group. The base logic then lives in one scenario, and specific partner groups get an uplift on top without duplicating it. See [Commission amount](https://paldock.com/knowledge-base/commission-amount/). #### Tracking API Here PalDock decides when to call. Nothing is arriving, so the scenario controls when to check, how often to try again, and when to give up. ##### Polling for a result The most common use. Ask the advertiser’s API what happened to a lead, and once it reaches a final state, update the transaction and read the value or commission out of the response. The usual shape: - **Start** node - **Wait** node, for example 12 hours, to give the advertiser time to process the lead before the first check. - **Modify Field** node if the request needs authentication built first, such as Base64-encoding credentials for a Basic auth header. - **HTTP** node, a GET to the advertiser’s status endpoint, using the advertiser’s own ID for the lead. - **Conditions on the connections leaving the HTTP node**, matching the status field in the response: A final rejected state : Set node writing `{result}` = rejected, then End. - A final approved state : Set node writing `{result}` = approved, and optionally `{commission}` straight from the response, then End. - Anything else, meaning still pending : into the retry loop. - **The retry loop** is a **Breaker** node plus a **Wait** node, looping back into the same HTTP node. The Breaker caps how many times it may repeat, for example six. Match the pending branch with *does not match* against the known final states, rather than listing every pending state the advertiser might invent. New states then land in the retry loop instead of being ignored. **When the Breaker limit is reached, the flow stops without a final state.** Nothing is written and nothing is retried. Those leads end up neither approved nor rejected, so decide separately what to do with them. Set the wait and the repetition count so the total window covers how long the advertiser realistically takes. Wait, check, branch, retry with a cap. That is the backbone of almost every polling integration. ##### Sending data to a partner The same mechanism in reverse: pushing data out to a specific advertiser or partner. From their side it looks like a postback arriving. From yours it is still a Tracking API, because PalDock decides when to call and what to send. Affiliates can create their own Tracking API postback. They become its owner and see it in their administration, and only their own data is ever sent to it. That restriction is locked and they cannot change it. As an admin you can also create a postback and assign an owner to it. The owner then sees it in their administration, exactly as if they had made it themselves. The difference is that you are not bound by the same restriction: you can assign an affiliate as the owner and still send them data covering everyone, not only their own. ##### Sending data to ad systems The same again, for forwarding conversions and events into advertising platforms. It can be set globally for the whole workspace, or scoped to individual accounts or campaigns. Both use the same conditions as everywhere else in PalDock, such as matching on result or comparing a value. --- ## Library of Integrations The **Integration Library** provides access to a large collection of ready-to-use integrations. Instead of building connections manually, you can add a prebuilt integration to your workspace with just a few clicks. #### Adding Integrations from the Library - Click **Add from Library** to open a drawer with a searchable list of available integrations. - The library includes: **Built-in integrations** provided by PalDock. - **Third-party integrations** created by external developers and shared through the library. - **Managed integrations** provided and maintained by PalDock. - Some integrations may be **paid**. To unlock them, payment is processed via PalDock credits. When you select an integration, it is added to your workspace **exactly as defined in the template**. This works as an import of the integration code, including parameters (which will initially be empty). 👉 **Important:** After adding an integration, you must fill in the required parameters (e.g. tokens, endpoints, credentials) before it can be used. #### Customization You may freely customize integrations and choose to sync them with the library for updates. Keep in mind that custom changes may conflict with future updates. If conflicts or issues occur, it is up to you to resolve them. #### Managed Integrations If you do not want to manage integrations yourself, PalDock also offers an **Integration Management Service**. In this setup: - You can add integrations as **managed integrations**. - Your tenant links to these managed integrations using an API token. - Managed integrations appear in your workspace with **limited editing rights**: You cannot delete fields or system parameters, but you can customize them (e.g. provide your own tokens). - Requests and core definitions are locked. - This approach ensures stability while still allowing minor customization where needed. #### Scope of Integrations The Integration Library is not limited to advertiser APIs. It also includes other common services, such as: - Facebook integrations for tracking. - Google Analytics or Google Ads integrations. - Email and SMS platforms. - Any third-party service exposed through an API. 👉 **Tip:** Use [global fields](https://paldock.com/knowledge-base/local-versus-global-fields/) whenever possible. Prebuilt integrations from the library are designed to map against them, making setup nearly instantly. --- ## Reject reason A reject reason says **why** a lead was not accepted. It turns a failed lead into information you can act on. ###### Always set one If no reason is defined, the lead falls into **Error**. Error means something broke, and it should stay that way. A lead the advertiser deliberately turned down is not a broken lead, and mixing the two makes both useless in reporting. So map a reason for every rejection path in your integration. If the advertiser gives you nothing to work with, fall back to a general one such as `Unspecified`. Any reason is better than none. ###### Keep the names short Reasons are aggregated in reports **by name**. Every distinct string becomes its own row. That means `Not Eligible` is a useful line in a report, while `We are not interested in this lead at the moment` is a line that will never group with anything and will never tell you anything. Keep reasons to one or two words, in English, and reuse the same wording everywhere. ###### How to set it The reason is stored in the `{reason}` parameter. There are two ways to write into it. **Modify node.** One node handles all your reasons, because you can define several conditions inside it. This is the recommended approach, otherwise you end up with twenty Set nodes and twenty connections just to cover the advertiser’s rejection responses. Example, mapping one advertiser response to a standard reason: - **Title:** Reject reason - **Field:** `{reason}` - **Source:** `parsedBody.status` (the field in the advertiser’s response) - **Operator:** Equals - **Value:** `This lead does not meet our criteria` - **Modification:** Set - **Output:** `Not Eligible` Add another section inside the same node for each further reason. **Set node.** Also possible, and it writes into `{reason}` the same way. But you need a separate [Set](https://paldock.com/knowledge-base/set/) node for every reason, each reached by its own connection with a condition. Use it only when that reason needs its own branch in the flow anyway. ###### What the run reports Every run ends in one of these, and the log tells you which. Three of them are not rejections at all, and knowing them apart is what stops you from hunting a bug that is not there. - **TIMED OUT** : something ran out of time, either the node, the whole run, or the pingtree. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). - **BREAKER** : a [Breaker](https://paldock.com/knowledge-base/breaker-node/) stopped a loop that had repeated as often as it was allowed to. - **DEAD END** : the flow reached a node and no connection leading out of it matched, so it simply stopped. Nothing was written and no End node was reached. - **The reason from a failed End node** : the flow finished properly and the value of `{reason}` is reported. This is the only one that is a real rejection, and it is empty when you did not set a reason. **Dead End is the one to watch.** It is the most common way an integration reports errors it does not really have, and it happens for a simple reason: most scenarios are built for the path where everything works. The advertiser then answers with something nobody planned for, no condition matches it, and the run stops mid-flow. The fix is not clever conditions, it is coverage. Go through the advertiser’s documentation, find every response they say they can return, and give each one a connection that leads somewhere. Anything you cannot enumerate goes down a catch-all branch, matched with a negative pattern against the responses you do know, ending in a failed End node with `Unspecified` as the reason. That way a lead you did not anticipate still arrives as a rejection you can read, instead of as an error you have to investigate. ###### Standard reasons You can invent your own, but stick to this list wherever it fits. Shared names are what make reporting comparable across advertisers. **At submit**, when the lead is sent to the advertiser: - **Cap** : the advertiser’s daily or monthly limit is used up - **Outside Hours** : outside the advertiser’s accepted hours - **Product Mismatch** : the data does not fit the product, such as amount, term, type, region or segment **At submit or by postback**, since the advertiser may find these out immediately or later: - **Duplicate** : the same application or order already exists at the advertiser - **Existing Customer** : already a customer, or in arrears with the advertiser - **Not Eligible** : fails a condition you could not check in advance - **Unspecified** : the advertiser rejected the lead and gave no reason - **Fraud** : suspected fraud or a false identity - **Blacklist** : the person is on the advertiser’s blocklist - **Invalid Traffic** : bots, cookie stuffing, self-referrals, incentivised traffic - **Test** : a test lead or order, not billed - **Age** : outside the product’s age range - **Verification Failed** : invalid document, unfinished BankID, missing paperwork - **Poor Credit** : bad history, low score, negative record in a credit register - **Low Income** : income below the threshold, or an unacceptable income type - **Too Much Debt** : debt and repayments too high relative to income - **Insolvency** : insolvency is in progress or has been filed - **Debt Collection** : enforcement or debt collection against the person - **No Bank Account** : no bank account, or it cannot be verified - **Out of Stock** : the goods are unavailable and the order cannot be fulfilled - **Not Available** : the service is not available at that location, such as coverage or connection - **Contract Locked** : tied to the current supplier, outside the notice period **By postback only**, once the advertiser has worked with the lead: - **Uncontactable** : could not be reached, contact details do not work - **Cancelled by Customer** : the person refused the offer or cancelled the order - **Cancelled by Advertiser** : the advertiser cancelled it, technically, manually or commercially - **Expired** : the offer was never opened and it expired - **Withdrawn** : withdrawn after the contract, such as goods returned or contract cancelled - **Payment Failed** : payment declined, card refused, proforma invoice unpaid - **Not Delivered** : not delivered, not collected, the address does not exist - **Chargeback** : payment reversed by the bank, which is a fraud signal rather than a withdrawal ###### Your own reasons If nothing on the list fits, create your own. Two rules: keep it short, and write it exactly the same way every time. A typo makes a second row in the report that looks like a second reason. --- ## Limits and timeouts PalDock applies several limits at the same time so that no flow can run forever or block the system. Most of them you will never reach. This page lists them all in one place, so you know where to look when a run stops earlier than expected. ###### Timeouts you set yourself Only two limits are yours to set, both on a node: - **HTTP request timeout**, on an HTTP node. How long the node waits for the external server to answer. - **Webhook waiting time**, on a Webhook node. How long the flow waits for an external system to call back. Everything below is a system limit. ###### System timeouts - **Node**: 5 minutes for one node from start to finish. - **Connection**: 1 minute to evaluate an arrow and hand over to the next node. - **Scenario run**: 250 minutes for the whole run, across all nodes and branches. - **Synchronous run**: 50 seconds for a scenario that runs while someone is waiting for the answer. - **Webhook waiting inline**: up to 40 seconds, when the node blocks the flow. - **Webhook waiting in the background**: up to 48 hours, when the flow is released and resumed later. - **Webhook data**: kept for 180 days after it arrives. The synchronous limit is the one that matters in practice. Form validation, autocomplete and leads sent over the API all run while a visitor or an API caller waits, so the whole flow has to finish inside it, not just one node. ###### Size limits - A scenario can have up to 50 nodes. - A single node can run at most 30 times within one run. A loop without a [Breaker](https://paldock.com/knowledge-base/breaker-node/) ends here, with the run stopped and an error in the log, so give every loop a Breaker that ends it sooner and on your terms. The limit of 30 is what protects you from a loop created by accident. If a node would run more often, the run is stopped and an error is written to the log. A **Breaker** node lets you set a lower limit yourself. ###### Retries A node runs once. There is no automatic retry, and a failed node does not repeat on its own. If you need a second attempt, build it into the flow with a condition on the response. ###### What happens when a limit is reached The run stops at that point and the reason is written to the run log. Branches that already finished keep their result. Nothing is retried silently. ###### Business limits The limits above are technical. Volume limits, such as how many leads or clicks an offer may take per hour or per day, are configured separately. See [Lead and Click Capping](https://paldock.com/knowledge-base/lead-and-click-capping/). --- ## Element types ### List of nodes A node is one action on the canvas. Nodes are joined by [connections](https://paldock.com/knowledge-base/connections-with-conditions/), which decide what runs next and can carry conditions, so the flow branches on the result. Different parts of PalDock use slightly customised versions of the Connection Creator, but the node types below are the same everywhere. ###### Start and End Every scenario begins with a **Start** node and every path should reach an **End** node. The Start node has a flow, which decides what triggers the scenario. In integrations there are two, Ping and Post, and each is a separate path with its own Start and its own End. Everywhere else there is one. A scenario can also be started by an internal event, such as a conversion or a status change, or by an external system calling in through a Webhook node. The End node records the outcome. Marked *success*, the lead goes through. Marked *failed*, it does not. See [Where Connection Creator is used](https://paldock.com/knowledge-base/where-connection-creator-is-used/). ###### Working with data **[Modify](https://paldock.com/knowledge-base/modify-field-in-connection-creator/)** changes the value of one or more fields, with conditions inside the node. This is where you translate your values into whatever the other side expects. **[Set](https://paldock.com/knowledge-base/set/)** stores a value from a response so it can be used later in the flow, or after it. **[Set Event](https://paldock.com/knowledge-base/set-event/)** records an event. For example, when a response comes back as a duplicate, increment the Duplicate counter by one so it shows up in reporting. **[Mirror](https://paldock.com/knowledge-base/mirror/)** inherits all settings from another node, so you maintain one master and the copies follow it. ###### Flow control **[Wait](https://paldock.com/knowledge-base/wait-node/)** pauses the flow before it continues. It can wait a fixed time, until a specific date and time, until a given hour of the day, until the next working day, or a set time after an event. **[Breaker](https://paldock.com/knowledge-base/breaker-node/)** limits how many times a loop may repeat, so a retry cannot run forever. There is no node that repeats something on its own. You build a loop from a Breaker, a Wait and a connection leading back to an earlier node. The Breaker is what caps it. **SubScenario** calls another scenario from this one and exchanges data with it, which keeps shared logic in one place instead of copied across integrations. ###### Requests **[HTTP node](https://paldock.com/knowledge-base/topics/connection-creator/element-types/http-node/)** sends a request to an external service. You set the method, endpoint, query, headers and body, plus the [format](https://paldock.com/knowledge-base/field-format/), the [timeout](https://paldock.com/knowledge-base/limits-and-timeouts/) and, where required, a [signature](https://paldock.com/knowledge-base/signature/). Authentication is part of this node, not a node of its own. API keys, Basic auth, OAuth and client certificates are all configured here, and an access token can be stored and refreshed. **[Webhook](https://paldock.com/knowledge-base/webhook-node/)** waits for an external system to call in. The flow pauses at the node and continues when the call arrives, which is usually better than polling when the other side supports it. ###### Related, but not nodes - **Connections** join nodes and carry the conditions. See [Connections with Conditions](https://paldock.com/knowledge-base/connections-with-conditions/). - **Keys** hold the tokens, endpoints and custom parameters an integration uses. - **[Structures](https://paldock.com/knowledge-base/topics/structures/)** define the fields a scenario works with. --- ### Start Every scenario begins with a Start node. It is the entry point: the flow starts here and runs immediately. The Start node itself does nothing to the data. It marks where the flow begins and what kind of flow it is. ###### The type follows the scenario A Start node belongs to one of the four contexts: Integration, Structure, Tracking or Feed. That decides what data the flow receives and what it is expected to give back. See [Where Connection Creator is used](https://paldock.com/knowledge-base/where-connection-creator-is-used/). Everything the scenario starts with is available from the Start node onwards: the fields of the structure the lead came from, the system parameters, and whatever arrived in the incoming request. ###### One Start, except in integrations Most scenarios have a single Start node. Integrations can have several, because an integration is really several separate flows sharing one canvas. In an [Offer pingtree](https://paldock.com/knowledge-base/distribution/) you choose a pingtree type on the Start node: - **Ping** asks the advertiser whether they want the lead, and at what price. - **Post** submits the lead. If you do not choose one, the Start node is a Post. Each of these is an independent path with its own Start and its own End. Never connect them. Some advertisers add a third step, where the lead has to be confirmed with a code sent to the customer. That verification also gets its own Start node. ###### It runs straight away Once the scenario starts, the Start node runs immediately. There is nothing on it to delay that. If the flow needs to wait before doing anything, put a [Wait](https://paldock.com/knowledge-base/wait-node/) node right after it. --- ### Connections with Conditions A connection is the arrow between two nodes. It decides what runs next. Left empty, it is always followed. Given a condition, it is followed only when that condition is met. ###### How a condition is built Three parts: - **Value**, what you are checking. - **Operator**, how it should be compared. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). - **Output**, what you are comparing it against. Some operators need two, such as *Is between*. Others need none, such as *Is true*. You can also give the condition a **Title** and **Subtitle**. These have no effect on the flow, they are labels shown on the arrow in the editor. Use them, because a canvas of unlabelled arrows is unreadable a month later. ###### Picking a value Both Value and Output have a picker, so you do not have to remember names. It offers four groups: - **Form Fields**, the fields of the structure the lead came from. - **Keys**, the tokens, endpoints and parameters the integration uses. - **System Parameters**, values PalDock fills in itself. - **Previous Steps**, everything produced earlier in the flow, including the parsed response body and the query of a previous request. There is no separate Source setting. Where the value comes from is decided by what you pick, so a field from a response body is picked under Previous Steps rather than selected as “body” somewhere. You can also type a value in directly, which is how you compare against a fixed string or number. Example: ``` `Value: {parsedBody.status} Operator: Equals Output: ok` ``` This connection is followed when the response body contains a `status` field set to `ok`. ###### Several conditions on one connection All of them must be true. There is no way to make them alternatives. ``` `{status} Equals 200 {parsedBody.valid} Equals true` ``` This is followed only when the call succeeded **and** the service said the value is valid. Checking only the body is a common mistake, because an error response usually has no `valid` field at all, and the connection then behaves in ways you did not intend. If you need alternatives, use two connections leading to the same node, each with its own condition. ###### Several connections from one node Every connection whose condition is met is followed. That is how the flow branches: one node leads to three others, and the response decides which paths continue. Two things follow from this: - **Make the conditions mutually exclusive**, unless you want more than one branch to run. Two conditions that can both be true will both fire. - **Cover everything.** If no connection matches, the flow stops there. Nothing is written, nothing is retried, and the run simply ends at that node. The safest way to cover everything is to match the known outcomes explicitly and catch the rest with a negative match against them, rather than trying to list every value the other side might return. ###### Branching on a response An advertiser returns a status and you want three outcomes: ``` `Rejected: {parsedBody.state} Regex match DEN|CAN Approved: {parsedBody.state} Equals APPROVED Pending: {parsedBody.state} Regex not match DEN|CAN|APPROVED` ``` Anything new the advertiser starts returning lands in Pending, which is where you want it, rather than falling out of the flow. ###### Common mistakes - **Braces in the wrong place.** Value takes a reference. Output takes what you compare against. Writing a field path into Output as plain text makes it a literal string that can never match. - **Relying on the status code alone.** Most advertisers return a rejection with a perfectly normal 200. - **Leaving no path for the unexpected**, so runs quietly end in the middle of the flow. - **Overlapping conditions** on branches that were meant to be alternatives. --- ### Modify in Connection Creator Advertisers rarely accept your data as it is. A phone number needs a prefix, a date needs a different format, your `full-time` has to become their `employed`. The Modify Field node is where that happens. Put it **before** the request, not inside it. Building values in the HTTP node works, but when something arrives wrong at the other end you have nowhere to look. Keeping the transformation in its own node means you can open the run and see exactly what went in and what came out. ##### How the node is organised One node holds as many sections as you need, and **each section is one target field**. Inside a section you define what happens to that field: - **Source**, where the value comes from. Usually the field itself, but it can be another field, or the result of an earlier step in the same section. - **Condition**, when the change should apply. Use *Always* when it should always happen. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). - **Modification**, what to do with the value. See [Modify Field](https://paldock.com/knowledge-base/topics/general-tools/modifications/) for the full list of operations. - **Output**, the result, for operations that need one. A section can hold several of these. That is how you map a list of values: one line per value, all in the same section, each with its own condition. ``` `Field: {income_type} equals full-time → employed equals self-employed → self-employed equals pension → pensioner` ``` One node, one place to look, instead of a branch per value. ##### Building a value in steps The lines in a section run in order, and a later line can take the output of an earlier one as its source. That is how you build a value in stages instead of looking for one operation that does everything. ``` `Field: {created_date} 1. source: {created_date} modify date → +30 days 2. source: step 1 format date → d.m.Y` ``` The second line formats the date the first line produced. Pick the earlier step in the Source setting, the same way you would pick a field. Keep this in mind when writing conditions. A condition on the second line is checked against whatever that line’s source holds at that moment, which may no longer be what the field contained when the node started. ##### Common uses - **Translating values.** Their vocabulary instead of yours, as above. - **Keeping a number within the advertiser’s range.** A numeric field can carry a value the advertiser will not accept. If they lend up to 20 000 and your form allows more, replace anything above that with 20 000, so the request goes through with the highest amount they can actually work with. - This is about the value in one field, not about how many leads an advertiser receives. For that, see [Lead and Click Capping](https://paldock.com/knowledge-base/lead-and-click-capping/). - **Filling empty required fields.** Some advertisers reject a request outright when a field is missing, even one they do not care about. Put a placeholder in. - **Reformatting.** Prefixes, date formats, splitting or joining values. - **Leaving a field out entirely.** Sometimes an empty value is worse than no value. Use [do-not-send](https://paldock.com/knowledge-base/do-not-send/) to drop the field from the request instead of sending it blank. ##### Watch the braces A reference goes in braces, as `{parsedBody.name}`. Written without them it is a plain string, so a condition can never match it and the whole section silently does nothing. This is the most common reason a Modify Field node appears to be ignored. --- ### HTTP node The HTTP request node is how a scenario talks to the outside world. Everything else on the canvas either gets data ready for it, or works with what it brought back. ###### Method The method has to match what the other side expects. If you get it wrong, the request fails even though the URL is perfect, and that is the first thing worth checking when something does not work. Integrations often use different methods at different steps, so check each request on its own. - **GET** asks for something. Parameters go in the URL and there is no body. You use it for status checks and validations. - **POST** submits something new. The data goes in the body. This is how leads are sent. - **PUT** replaces a whole record. - **PATCH** changes only part of one. - **DELETE** removes a record. With leads that usually means a cancellation. - **HEAD** asks only for the headers. Handy when you just want to know whether the endpoint is alive. - **OPTIONS** asks what the endpoint supports. You will rarely need it. ###### Endpoint The URL the request goes to. Rather than typing the full URL into every request, store the base as a parameter and write `{endpoint}/register-lead`. Then you have one place to change it when the advertiser moves their API, and you can point everything at a sandbox by swapping a single value. If you put query parameters straight into the URL, they are kept. PalDock merges them with anything you add in the query list, so you can use whichever is more convenient. ###### Pingtree type You only need this when the integration runs in a [pingtree](https://paldock.com/knowledge-base/distribution/). It tells PalDock whether this request is the ping, the post, or the post verification. Leave it empty and PalDock treats the flow as a post. That is fine while the integration has one flow. As soon as you want a second Start node on the canvas, both need a type, otherwise PalDock cannot tell which one to run. ###### Format The format decides how the body is packaged. The other side accepts one and rejects everything else, so read their documentation instead of guessing. - **JSON** sends an object in the body. Most modern APIs want this. - **form-data** uses multipart encoding, typically for file uploads. - **x-www-form-urlencoded** sends `key=value` pairs joined with `&`. Older APIs often want this. - **x-www-form-urlencoded + JSON** is a hybrid: parameters are URL encoded, but a field can still carry JSON. - **login-pass-data** sends credentials alongside the data, for APIs that do not use tokens. This setting covers the whole request. Individual fields can still be nested inside it, and [Field format](https://paldock.com/knowledge-base/field-format/) explains how. ###### What goes in the request **Query** parameters are added to the URL. They are usual for GET, but they work with any method. **Headers** carry everything around the data: content type, authorisation, and whatever custom keys the API asks for. **Body** is the payload itself, for POST, PUT and PATCH. Every value is a plain text field. You type what you need and use the picker to drop in a reference, which shows up as a tag but is stored in braces, like `{data_first_name}`. You can mix the two, so `Bearer {token}` and `{first_name} {last_name}` both work. PalDock adds `User-Agent: CC/2.0` and `Accept: application/json` on its own. If you set either of them yourself, yours is used instead. ###### Empty and missing values Some APIs care about the difference between an empty string, a null, and a field that is not there at all, and they will reject the request if they get the wrong one. Two settings handle it, and both apply to the query and the body. **Convert blank values** changes the value before it goes out: - empty string to null - null to empty string - missing to null - missing to empty string - empty string or missing to null - null or missing to empty string **Skip field when** drops the field from the request altogether: - null - empty string - missing - null or empty string - missing or empty string - null or missing - null, missing or empty string The difference is what actually arrives. Convert sends a different value, Skip sends nothing. When an API rejects a null but is perfectly happy if the field is not there, Skip is what you want. ###### Parser The parser decides how the response is read. Choose JSON or XML and PalDock turns the response into something you can address field by field, like `{parsedBody.leadId}`. Anything else is left as plain text, and `{parsedBody}` stays empty. If you leave the parser alone, PalDock goes by the content type the other side declared. Set it yourself when they declare the wrong one, which happens more often than you would expect with older APIs that return JSON but label it as HTML. Watch out for this one, because it fails quietly. The request goes through, the status is 200, and every condition reading `{parsedBody.something}` finds nothing at all. If your conditions behave as though the response were empty, look here first. ###### Insecure PalDock normally checks the certificate of the server it is calling, and refuses to send anything if the certificate is expired, self signed, or belongs to a different host. Turning on insecure skips that check. It is there for a partner’s test environment with a self signed certificate. On production it means you no longer know for certain who is receiving your lead data, so use it to get unblocked and then ask them to fix the certificate. ###### Timeout The timeout is how long the request waits for an answer before giving up. It is a ceiling, not a delay, so if the answer comes back in half a second, the flow carries on in half a second. Keep it short inside a [Structure](https://paldock.com/knowledge-base/topics/structures/), because the customer is sitting in front of the form the whole time. There are also limits on the node, the run and the scenario above this one. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ###### Authentication There is no separate authentication node. Credentials go into the request like any other value, usually as a header. **A static token or API key** is the easy case. Store it as a parameter and use it: ``` `Authorization: Bearer {token} X-Api-Key: {token}` ``` **Basic auth** takes one more step, because the header carries a single encoded string rather than two values: - A **Set** node joins them, for example `{auth0}` = `{client_id}:{client_secret}`. - A **Modify Field** node runs `to-base64` on it and writes the result into `{auth}`. - The header then reads `Authorization: Basic {auth}`. **A token you have to fetch**, as with OAuth or JWT, needs its own request before the real one: - An **HTTP** node calls the token endpoint. These endpoints usually want `x-www-form-urlencoded` with `grant_type` in the body, and are themselves protected by Basic auth as above. - The connection leaving that node checks that a token actually came back, for example that `{parsedBody.access_token}` is not empty. Skip this and the flow carries on with an empty token, and every request after it fails for reasons that make no sense. - A **Set** node stores it as `{token}`. - Everything after that sends `Authorization: Bearer {token}`. That auth call is a normal node, so it takes its own time and counts against the limits. If several requests in one flow would each fetch the same token, fetch it once at the start instead. ###### Signature When the other side wants signed requests, use the Signature setting rather than building the signature by hand. PalDock covers MD5, HMAC, Digest and HTTP Signatures through presets. See [Signature](https://paldock.com/knowledge-base/signature/). ###### What you get back Everything the request produced is available to the nodes after it: - **`{status}`** is the HTTP status code. - **`{parsedBody}`** is the parsed response, addressed with dots, as in `{parsedBody.offers.0.offerId}`. - **`{body}`** is the raw response as text, whether it parsed or not. - **`{headers}`** are the response headers. - **`{uri}`** is the URL that was called. - **`{query}`**, **`{request_body}`** and **`{request_headers}`** are what PalDock actually sent. Those last three are the ones to reach for when a request is rejected and you cannot work out why. They show what really left PalDock, rather than what you meant to configure. ###### Before and after **Before the request**, use [Modify](https://paldock.com/knowledge-base/modify-field-in-connection-creator/) to get values into the shape the other side wants. Doing it there instead of inline means that when a value arrives wrong, you can see where it came from. **After the request**, put conditions on the connections leaving the node to work out what the response means, and use [Set](https://paldock.com/knowledge-base/set/) to keep what you need, usually `{external_id}` and `{redirect_url}`. ###### Common mistakes - The wrong method with the right URL. - The wrong format with the right method and URL. - Treating any 2xx as acceptance. Most rejections arrive with a perfectly normal status code. - The wrong parser, so every condition reads an empty body and nothing ever matches. - No check that the token request actually returned a token. - The base URL typed into every request instead of stored as a parameter. --- ### Field format Most APIs do not want a flat list of values. They want objects inside objects, or lists of them. In PalDock you do not build that structure anywhere, you write it into the field name and PalDock assembles the payload from it. ##### Objects A dot means “inside”. Everything before the dot is the object, everything after it is the field within it. ``` `customer.name customer.email` ``` sends json ``` `{ "customer": { "name": "John Doe", "email": "john.doe@example.com" } }` ``` Nest as deep as the API needs, one dot per level: `customer.address.city`. ##### Lists A number means a position in a list. Counting starts at zero, so the first item is `0`. ``` `orders.0.product orders.0.price orders.1.product orders.1.price` ``` sends json ``` `{ "orders": [ { "product": "Laptop", "price": "1200 EUR" }, { "product": "Phone", "price": "650 EUR" } ] }` ``` The same works for a list inside a list. `data.0.0` and `data.0.1` are the first and second value of the first list: json ``` `{ "data": [ ["first", "second"] ] }` ``` ##### Mixing them Objects and lists combine freely, because both are just steps along the same path. ``` `customer.name customer.email orders.0.product orders.1.price` ``` If it helps, think of an object as a folder and a list as a numbered set of files inside it. The field name is the path that gets you to the exact spot. ##### Order does not matter You do not have to keep related fields together in the editor. PalDock groups them by name when it builds the request, so these four produce exactly the same payload whichever order they appear in: ``` `customer.name orders.1.price customer.email orders.0.product` ``` Sort them however makes the editor easiest to read. ##### Getting it right Check the API documentation for the structure they expect and copy it path by path. If you have an example payload from them, [jsonpath.com](https://jsonpath.com/) with JSONPath Plus is a quick way to confirm which path leads to which value. The same notation works in the other direction. When you read a response, `{parsedBody.offers.0.offerId}` walks the same path through what came back. --- ### HTTP Signature Some partners want every request signed. The signature proves two things: that the request came from you, and that nobody changed it on the way. They compute the same signature on their side and compare. PalDock does the signing. You choose a preset that matches what the partner’s documentation describes, and PalDock builds the signature from the request as it is being sent. Presets are fixed and you cannot write your own signing rule. If a partner needs one we do not have yet, tell us and we will add it. ###### The settings - **Preset** decides what gets signed and how. - **Hash** is SHA-256 or SHA-512. The partner will say which. MD5 presets do not have this choice. - **Delimiter** is the character used to join values before hashing, either `|`, `&` or `.`. Only presets that join values need it, and the partner’s example will show you which one they use. - **Position** decides whether your secret goes before the data or after it. Prefix puts it first, suffix puts it last. MD5 presets need this, and the partner’s example is the only way to tell which they expect. ###### Secrets Store the signing credentials as parameters in the integration: - **`sign_secret`** is the shared secret. Every MD5 and HMAC preset needs it. - **`sign_keyid`** is the key identifier that goes into the signature header. Only HSIG needs it. If one is missing when the request runs, the node fails and the log says which. ###### Where the signature ends up This is the step people miss, and the failure is silent. - **MD5 presets add it to the body themselves.** A `signature` field appears in the payload. You do nothing. **Every other preset gives you tags** and you place them in the headers yourself: - `{signature}` is the signature - `{digest}` is the digest, where the preset makes one - `{timestamp_sign}` is the timestamp that was signed - `{random_sign}` is the nonce, for the preset that uses one If the partner asks for the signature in `X-Signature`, you add that header with `{signature}` as its value. Forget it and the request goes out unsigned, which the partner usually answers with a bare 401. When a preset signs a timestamp, PalDock also adds a `Timestamp` header on its own, so what it signed and what the partner sees are always the same value. ###### A complete example The partner’s documentation says: *sign the raw JSON body with HMAC SHA-256 and send it in X-Signature.* In the request: ``` `Method: POST Endpoint: {endpoint}/leads Format: JSON Body: first_name {first_name} last_name {last_name} email {email}` ``` In the headers: ``` `X-Signature: {signature}` ``` In the Signature card: ``` `Preset: HMAC · Body Hash: SHA-256 Delimiter: |` ``` And in the integration parameters: ``` `sign_secret: the key they gave you` ``` That is everything. PalDock builds the body, signs it, and replaces `{signature}` in the header before the request leaves. ###### Picking the preset Look for these phrases in the partner’s documentation: - “signature from the request body” is **HMAC · Body** - “HMAC(timestamp + body)” or anything about replay protection is **HMAC · Unix Timestamp + Body** - a date header in HTTP format, like `Tue, 11 Aug 2026 10:00:00 GMT`, is **HMAC · RFC 7231 Date + Body** - “sign the JSON exactly as sent”, with a timestamp, is **HMAC · Unix Timestamp + JSON Body** - “parameters sorted alphabetically”, or an example with sorted keys, is **HMAC · Params A→Z** - a nonce alongside the timestamp, method and path is **HMAC · Params A→Z + Nonce + Body Hash** - “send a Digest header”, or `Digest: SHA-256=…`, is **Digest · Body (Base64)** - “HTTP Signatures”, “Authorization: Signature”, “signed headers”, or `(request-target)` is **HSIG + Digest** - an MD5 example, or a hash of joined values with a secret, is one of the MD5 presets Other terms worth searching their docs for: canonical string, X-Signature, Base64, nonce, SHA-256, SHA-512. ###### MD5 presets These join the body into one string, add your secret, and hash the result with MD5. They differ in how that string is built. **Values** takes only the values: ``` `value1|value2|value3|secret` ``` **Key=Value** takes the field names too: ``` `first_name=John&last_name=Doe&secret` ``` **As-sent** keeps the order from the request editor. **A→Z** sorts by field name first. If the partner’s example shows the fields in alphabetical order, you want A→Z. Where the secret sits is set separately, with Position. The two examples above both put it at the end, which is the common case, but some partners expect it at the front. Nested fields are flattened to their dotted names first, so `customer.name` is signed as `customer.name`. The presets: - MD5 · Values · As-sent - MD5 · Values · A→Z - MD5 · Key=Value · As-sent - MD5 · Key=Value · A→Z ###### HMAC presets These sign with your secret, which is what makes them stronger than a plain hash. They differ in what exactly they sign. - **HMAC · Body** signs the body values joined with the delimiter. - **HMAC · Unix Timestamp + Body** puts a Unix timestamp in front, so an intercepted request cannot be replayed later. - **HMAC · RFC 7231 Date + Body** is the same, with the timestamp written as an HTTP date. - **HMAC · Unix Timestamp + JSON Body** signs the timestamp followed by the body as JSON, rather than joined values. Use it when the partner signs the exact JSON they receive. - **HMAC · Params A→Z** sorts the body fields by name and signs them as `key=value` pairs. Note that this covers the body, not the query. - **HMAC · Params A→Z + Nonce + Body Hash** builds a canonical string from the timestamp, a nonce, the method, the path, the sorted query and a hash of the body, then signs that. Use it when the partner asks for a nonce. ###### Digest - **Digest · Body (Base64)** hashes the body and Base64 encodes it, which is what goes into a `Digest` header. It needs no secret, because it only proves the body is intact, not who sent it. Partners usually ask for it alongside another signature rather than on its own. ###### HSIG - **HSIG + Digest (Base64) · SH (TS,H,RT,DIG) NL LC · HMAC** is the full HTTP Signatures scheme. PalDock builds a canonical string from four lines, in this order: the request target, the host, the digest and the timestamp. It signs that string and produces a complete header including your key id and the algorithm, ready to place with `{signature}`. When the request has no body there is no digest, so that line is left out and only the other three are signed. This preset needs both `sign_secret` and `sign_keyid`. ###### When it does not work - **The tag is missing.** The signature was calculated and thrown away. Check the headers first. - **Body signing is byte sensitive.** Whitespace, JSON formatting and field order all change the result. If the partner rebuilds the body their own way before checking, the signature will never match, however correct your preset is. This is the hardest one to spot, and the only way through it is to compare the exact bytes with them. - **The wrong delimiter.** The signature is computed, sent, and rejected. There is nothing in the response to tell you it was the delimiter, so if everything else matches their documentation, try the others. - **The wrong position.** Same story. The secret at the front instead of the back gives a completely different hash, and the rejection looks identical either way. - **The wrong scope.** Check whether they sign the body only, or the query as well. Most presets here sign the body. - **No body.** Most presets need one and the node fails without it. --- ### Set The Set node stores a value so you can use it later. Most often you take something out of a response and keep it: the advertiser’s ID for the lead, the URL to send the customer to, the price they quoted. The value is written to the database, so it survives the run. It is available to the rest of the flow, and afterwards to tracking and postbacks. ###### How it works Each line has two fields. - **Key** is the variable you are writing into, in braces, for example `{external_id}`. - **Value** is what goes into it. Use the picker to take something an earlier node produced, or type a fixed value. ``` `Key: {external_id} Value: {parsedBody.applicationId}` ``` Read it left to right: put `applicationId` from the response into `external_id`. The name on the right is whatever the advertiser calls it in their response, so it will be different for every partner. There is no Source setting. Where the value comes from is decided by what you pick, so a field from the response body is picked under the previous step rather than selected as “body” somewhere. One node holds as many lines as you need, so a single Set node after a request usually stores everything you want from it: ``` `Key: {external_id} Value: {parsedBody.applicationId} Key: {redirect_url} Value: {parsedBody.offerUrl}` ``` ###### Store the external ID `{external_id}` is the advertiser’s own identifier for the lead, and it is the one value worth storing in almost every integration. Once the lead is delivered, everything that happens to it afterwards happens on the advertiser’s side. When they later report that it was approved, rejected or paid, they refer to it by their own ID, because yours means nothing to them. If you never stored it, that report arrives with nothing to attach it to, and the conversion is never confirmed. The same ID is also what stops the same conversion being counted twice. See [Deduplication](https://paldock.com/knowledge-base/deduplication/), [Deduplication based on advertiser’s ID](https://paldock.com/knowledge-base/deduplication-based-on-advertisers-id/) and [Tracking S2S Postback](https://paldock.com/knowledge-base/tracking-s2s-postback/). Store it even when you cannot think of a use for it today. It costs one line, and there is no way to go back for it later. ###### Other variables worth knowing - **`{redirect_url}`** is where the customer goes next, when the advertiser returns a link. - **`{price}`** is what the advertiser bid for the lead. You need it in an auction, where the bids decide who wins. See [Pingtree Distribution](https://paldock.com/knowledge-base/distribution/). - **`{reason}`** is why a lead was rejected. Worth setting on every rejection path, otherwise the lead lands in Error and tells you nothing. See [Reject reason](https://paldock.com/knowledge-base/reject-reason/). - **`{commission}`** is what the affiliate earns. You rarely set this in an integration, because commissions are normally worked out from the commission settings rather than from the advertiser’s answer. Anything else you store is yours to name and use: a token the next request needs, a value you want to pass onwards, a flag you check in a later condition. ###### Reading from a response The picker offers everything the earlier nodes produced. Under a previous step you will find its whole result, not only the body, so you can store the status code, a header, or the raw response just as easily as a parsed field. - **`{parsedBody.…}`** is the parsed body. Follow the structure with dots, and use a number for a position in a list, as in `{parsedBody.offers.0.offerUrl}`. - **`{status}`** is the HTTP status code, which is worth storing when you want to see later what the advertiser actually answered. - **`{body}`** is the raw response as text, for when it did not parse. - **`{headers}`** are the response headers. If everything you pick out of `{parsedBody}` comes back empty, check the parser on the [HTTP request](https://paldock.com/knowledge-base/topics/connection-creator/element-types/http-element/) node before looking anywhere else. ###### Building a value for the next request Storing a response is the common use, but a Set node is also how you prepare something the next node needs. Joining two parameters before encoding them, for example, is a Set node followed by a Modify Field node: ``` `Key: {auth0} Value: {client_id}:{client_secret}` ``` A value can mix fixed text and references freely, which is what makes this work. ###### When the value depends on the answer A Set node writes what you give it, every time. It has no conditions of its own, so to store one thing on one answer and something else on another, each case needs its own connection with a condition and its own Set node at the end of it. That is fine for two or three cases. Beyond that the canvas fills up with nodes that all do nearly the same thing. [Modify Field](https://paldock.com/knowledge-base/modify-field-in-connection-creator/) is the better tool there, because the conditions sit inside the node. Twenty rejection responses mapped onto your own reasons is one Modify Field node with twenty lines, rather than twenty Set nodes and twenty connections. The rule of thumb: Set node when the value is simply there, Modify Field when you have to work out what it should be. ###### An empty Set node is allowed A Set node with no lines does nothing to the data, and that is sometimes what you want. On a branch where the answer is “we looked and found nothing”, it leaves the field empty and lets the flow carry on to the End node, which keeps that branch visible on the canvas instead of leaving a loose end. ###### Common mistakes - **The two fields swapped.** Key is where the value lands, Value is where it comes from. The wrong way round, and you store the literal text into a variable named after a response field. - **Missing braces.** A reference without braces is just text. - **Not storing `{external_id}`.** Everything looks fine until the first postback arrives and matches nothing. --- ### Wait The Wait node pauses the flow, then lets it continue. You use it when the other side needs time before it can answer, and when a retry loop should leave a gap between attempts. ###### How long You set the delay in seconds, minutes or hours. The maximum is one year. ###### What the pause actually does This is the part worth understanding, because a Wait behaves differently depending on whether anyone is waiting for the answer. - **In a background flow**, the pause costs nothing. The run is put down and picked up again when the time is up. A Wait of twelve hours before checking a lead’s status is perfectly normal. - **In a flow that runs while someone waits**, such as an integration in a pingtree, a short pause genuinely holds everything up. The customer sits on the loading screen for exactly as long as you set. The dividing line is around fifty seconds. Below that, the flow simply stops and waits, and the customer waits with it. Above that, PalDock releases the flow instead of holding the line open, and picks it up later in the background. That sounds convenient, but it means the answer arrives long after the customer has gone. A long Wait in a pingtree is not a way to give an advertiser more time, it is a way to lose the sale. See [Limits and timeouts](https://paldock.com/knowledge-base/limits-and-timeouts/). ###### Waiting in a loop The usual pattern is: ask, and if the answer is not final yet, wait and ask again. ``` `Get status → still pending → Breaker → Wait → back to Get status` ``` Always put a [Breaker](https://paldock.com/knowledge-base/breaker-node/) in that loop. Without one the flow keeps going round until it hits a system limit and fails with an error, which tells you nothing useful about the lead. Set the delay and the Breaker limit together, because what matters is the total. Six attempts twenty-four hours apart covers a week. Six attempts a minute apart covers six minutes, which is not long enough for anything a human has to look at. ###### Common mistakes - **A Wait in a pingtree with no thought for the customer.** Every second is a second they are staring at a loading screen. - **A loop with no Breaker.** It runs until it errors out. - **A delay that is too short for the advertiser.** If they take a day to decide, asking again in five minutes just wastes six requests and ends with nothing. --- ### Breaker The Breaker node caps how many times a loop can repeat. It is what turns a retry into something that finishes. ###### How the count works You set a number of repeats. The flow may pass through the Breaker that many times. On the next arrival, the Breaker stops it. Set it to 2 and the flow goes through twice. The third time it arrives, the run stops there. So the number is how many passes you allow, not how many times it may loop back. With a loop that asks an advertiser for a status, a Breaker set to 6 means six questions asked. ###### What stopping means The run ends at the Breaker. Nothing further happens on that branch, no End node is reached, and no result is written. That has a consequence worth planning for: those leads are neither approved nor rejected. They are simply unresolved. Decide what you want to do with them, because nothing will happen to them on its own. Other branches are unaffected. Only the branch that hit the Breaker stops. ###### Choosing the limit Work backwards from how long the advertiser realistically takes, then divide by your Wait. - Answers within minutes: a Breaker of 3 with a Wait of one minute. - Answers within a day: a Breaker of 6 with a Wait of four hours. - Answers within a week: a Breaker of 6 with a Wait of a day. Add a little margin, but not much. Every extra attempt is another request to the advertiser’s API for a lead that is looking less likely with each one. ###### Why you always want one A loop without a Breaker does not run forever, but the way it ends is worse than stopping cleanly. PalDock allows a single node to run at most thirty times within one run, and past that the whole run fails with an error. An error is meant to mean something broke. A lead the advertiser never got round to deciding on has not broken anything, and you do not want the two mixed together in your logs. In a pingtree there is a second reason. A loop that keeps going holds up the channel, and the pingtree cannot move on to the next advertiser while it waits. ###### Common mistakes - **No Breaker at all**, so the loop ends in an error instead of a decision. - **A limit set without looking at the Wait.** The two only mean something together. - **Forgetting about the leads that hit the limit.** They stay unresolved until you go looking for them. --- ### Webhook A Webhook node pauses the flow and waits for an external system to call you. You need it when an advertiser accepts the lead but cannot say straight away what happened to it. Instead of asking them again and again, you give them a URL and they call it once they know. That is usually faster and always cheaper than polling. ###### Two ways to wait The setting **Pingtree waits until webhook finishes** decides how the pause works, and the difference matters more than it looks. - **Switched on**, the flow holds the line open. The pingtree stops and waits, the customer sits on the loading screen, and as soon as the call arrives the flow carries on with the data. Because something is genuinely blocked the whole time, the timeout here is capped at about 40 seconds. Use it only when you are confident the advertiser answers within seconds. If they do not, you have held up the sale for nothing. - **Switched off**, the flow is put down instead. Nothing is blocked, the pingtree moves on, and the run is picked up again when the call arrives. The wait can be as long as 48 hours. This is the right choice for anything the advertiser has to think about, and for anything a human on their side is involved in. ###### What happens when nobody calls The two modes behave differently here as well, which is worth knowing before you pick one. - **Waiting on the line**, a timeout is an error. The run stops and the log says the webhook timed out after so many seconds. - **Released**, a timeout is not an error. The flow simply carries on when the time is up, with none of the data it was hoping for. Put a condition on the connection leaving the node to check whether anything actually arrived, otherwise the flow continues as though it had an answer. ###### Webhook ID Each webhook needs its own ID, and it forms part of the URL you hand to the advertiser. Keep a note of it. If you delete the webhook and build it again later, you can reuse the old ID so the advertiser never has to change anything on their side. ###### Endpoint The URL the advertiser calls. Give it to them together with whatever identifier they should send back. ###### How the call finds the right lead An incoming call has to be matched to the exact run that is waiting for it, and PalDock uses the same two methods as everywhere else in tracking. See [Tracking processing](https://paldock.com/knowledge-base/tracking-processing/). - **By the PalDock conversion ID.** This is the identifier PalDock generated for the lead, and it is unique across the system, so on its own it is enough. Send it to the advertiser when you submit the lead and ask them to return it. - **By the advertiser’s external ID.** Their own identifier for the lead, which is unique only in combination with the advertiser ID. This is why you store `{external_id}` from the response when the lead is submitted. See [Set node](https://paldock.com/knowledge-base/set/). If the call matches nothing, the advertiser gets back: ``` `{"code":404,"message":"Waiting Webhook not found for provided token and identifiers"}` ``` That response means one of three things: - the run already timed out and stopped waiting, - the identifier they sent is not the one you stored, - or they called the wrong webhook. ###### When the advertiser uses different parameter names Advertisers rarely call these identifiers what you call them. One sends `lead_id`, another sends `operationId`, and PalDock does not recognise either. You do not have to accept their naming. In your workspace settings, under **Custom ID parameter names in integrations**, you list the names they use, and PalDock treats those as the identifier. There are three fields, one for the PalDock conversion ID, one for the advertiser ID, and one for the advertiser’s own ID. Each accepts several names separated by commas, so one setting covers all your advertisers. Fill this in before you go live rather than after. Without it every callback comes back as a 404, and there is nothing in that response to suggest the parameter name is what is wrong. ###### Using what arrived Everything from the call is available to the nodes after the Webhook, split into four parts: - **body**, what they posted - **queries**, the query parameters in the URL - **headers**, the request headers - **cookies**, any cookies they sent Branch on it the same way you would on a response. A callback often carries several kinds of event, so read the field that says which one it is and give each its own connection. Anything you do not recognise should have a path too, otherwise the run ends there. The data stays available for 180 days. ###### Retrying A webhook that never arrives is common enough to plan for. The usual pattern gives it a second chance rather than giving up: ``` `Webhook → nothing useful → Breaker → Wait → back to Webhook` ``` See [Breaker](https://paldock.com/knowledge-base/breaker-node/) and [Wait](https://paldock.com/knowledge-base/wait-node/). ###### Starting a scenario with a webhook A Webhook node can also be the first node in a scenario, rather than a pause inside one. Then it is not waiting for anything in particular, it just runs whenever the URL is called. That is how you handle an advertiser who sends updates on their own schedule, without a lead of yours waiting for them. ###### Common mistakes - **Holding the line open when the advertiser takes minutes.** The customer leaves long before the answer arrives. - **No check that the data actually came.** In released mode a timeout looks exactly like a successful call to the nodes that follow. - **Not storing `{external_id}`**, so their call has nothing to match against. - **Their parameter names not registered**, so every call comes back as a 404. - **Changing the webhook ID** and not telling the advertiser. --- ### End trigger The End node marks how a flow finished. Every path should reach one. There are two settings you can choose: - **Success**, the other side accepted the request. - **Reject**, the other side turned it down. ###### Error is what happens without an End node Error is not a setting. It is where a flow lands when it never reached an End node at all, whether because something broke, or because no connection matched and the run simply stopped. That is why marking every path explicitly matters. A rejection is a normal outcome, and if it is left to fall into Error, it stops looking like a business result and starts looking like a fault. Error should stay reserved for things that are actually broken, so it remains useful in logs and worth being notified about. Check every branch of your flow leads somewhere. A branch that trails off without an End node is the most common way leads end up in Error for no reason. ###### Give a rejection a reason A rejection on its own tells you the lead was not taken. A reason tells you why, and that is what shows up in reports, aggregated across all your integrations. Whatever the advertiser sends back can be mapped onto your own set of reasons, or onto the standard ones, so that rejections from different advertisers are comparable. See [Reject reason](https://paldock.com/knowledge-base/reject-reason/). --- ### Set Event The **Set Event** element lets you trigger and record custom events during the flow. This can be used to track specific outcomes or behaviors returned by an integration. - **Set Event** – defines an event name and action. - Common usage: when a response meets certain conditions (e.g. “Duplicate”), PalDock can log the event and, as a result, update the corresponding data in reporting - Events are stored in the system and can be used for reporting, monitoring, or triggering other actions. **Example:** If the API returns a “Duplicate” response, you can configure a Set Event to increment a metric for **Duplicate **leads by +1. --- ### Mirror The **Mirror** element allows you to reuse the configuration of another element without duplicating it. - A Mirror **inherits all settings** from a selected “master” element. - Any changes made to the master are automatically applied to all its mirrors. - The mirror itself **cannot be modified** – you can only switch it to point to a different parent element. - This is useful when the same request or configuration must be used in multiple places, but you want to maintain it in a single location. This approach reduces duplication and ensures consistency across integrations. --- # General tools ## Condition Operators and values Operators are used wherever PalDock compares one value against another: - [Connections](https://paldock.com/knowledge-base/connections-with-conditions/) in the Connection Creator - [Modify Field](https://paldock.com/knowledge-base/modify-field-in-connection-creator/) - [Table filters](https://paldock.com/knowledge-base/filters/) - [Pingtree filters](https://paldock.com/knowledge-base/offer-and-pingtree-filters/) The set is the same everywhere, with one exception noted below. ###### Operators Most operators need one value to compare against. A few need two, and some need none at all. **Comparing** - **Equals** : the two values are the same - **Not equals** : the two values are different - **Is less than** : lower than the given value - **Is less than or equals** : lower than or equal to it - **Is greater than** : higher than the given value - **Is greater than or equals** : higher than or equal to it - **Is between** : between two boundaries, boundaries excluded. Needs a second value - **Is between (inclusive)** : between two boundaries, boundaries included. Needs a second value **Text** - **Contains** : the text contains the given substring - **Does not contain** : the text does not contain it - **Starts with** : the text begins with it - **Ends with** : the text ends with it - **Regex match** : the value matches the given pattern - **Regex not match** : the value does not match it **State** - **Is true** : evaluates to true. No value needed - **Is false** : evaluates to false. No value needed - **Is empty** : empty string, empty list, or nothing at all. No value needed - **Is not empty** : has some value. No value needed **Modify Field only** - **Always** : always applies. Use it when the change should happen unconditionally, with no condition to write ###### Field value The value you compare against is a plain text field, but it also accepts a regular expression. One condition can then cover several cases, so you do not have to build a separate step for each of them. Compare the two. A single value, in Modify Field: ``` `Source: this field Operator: Equals Value: approved Operation: anything Output: anything` ``` Several values at once, using a pattern: ``` `Source: this field Operator: Regex match Value: approved|rejected Operation: anything Output: anything` ``` The second one does the work of two steps. With ten possible statuses it does the work of ten, and everything stays visible in one place instead of being spread across the canvas. Note the operator. **Equals compares the text exactly**, so `approved|rejected` would be treated as one long string and would never match anything. Patterns need **Regex match**. The **Field** setting only appears when the Source is set to another field. ###### Patterns worth knowing - `|` for alternatives, as in `approved|rejected` - `.*` for anything, as in `app.*` - `^` and `$` to anchor to the start and the end, as in `^approved$` Standard regular expressions are supported, so anything you would normally write works here too. The anchors matter more than they look. Without them, `approved` also matches `not approved`, and a rejection quietly travels down the success branch. --- ## Group changes Bulk Edits allow you to make changes to multiple rows in a table at once, instead of editing them one by one. This feature saves time and ensures consistency when managing larger datasets. #### How It Works - **Hidden by default** – checkboxes for row selection only appear when you hover over the header or the first column of a row. - **Select rows** – choose one or more rows manually - **Click Edit** – once rows are selected, the **Edit** button becomes active. - **Set up bulk changes** – define what you want to do using the available options (see below). - **Apply changes** – you can update, delete, or otherwise modify selected rows. #### Available Options When performing a bulk edit, the following options are available: - **Rows** – the rows you selected manually, or those imported by pasting a list of IDs/values (for example from a previously exported and modified Excel file). - **Action** – what should happen (e.g. *Edit*, *Delete*). - **Field** – which field/column should be updated (includes both visible and hidden editable fields). - **Value** – the new value to insert. ⚠️ **Important:** Bulk edits will **overwrite existing values** in the selected rows with the new ones you provide. Any current values that are not specified in the update will be permanently lost. #### Typical Use Cases - **Transaction Report** – Change statuses or approve multiple transactions at once - **Offer Management** – Update tags, categories, access levels, or location for multiple offers - **General Management** – Apply bulk changes to affiliates, advertisers, commissions, or other entities Basically, anywhere in PalDock where you can edit items individually in a table, you will also be able to apply bulk edits. --- ## Parameters Almost every field in the Connection Creator asks you for a value. You can type it, but usually you pick it, and the picker shows you everything the scenario has available at that point. There are four groups. ##### Form fields The fields of the structure the lead came from, such as `first_name` or `email`. What appears here depends on the offer, so two integrations rarely show the same list. ##### Keys The tokens, endpoints and credentials this integration uses. Store anything you would otherwise repeat, such as the base URL or an API key, and change it in one place. ##### System parameters Values PalDock fills in itself. Always available, never something you set. The full list is below. ##### Previous steps Everything the earlier nodes produced. Each node appears by name, and under it whatever it returned. What that is depends on the node, so this part of the picker looks different in every scenario and changes as you build. An HTTP node gives you the most: the status code, the parsed response body, the headers, and what was actually sent. Other nodes give you what they produce. Only nodes that ran before this one are here, because data travels forward and never back. ##### How a value is written Picked values appear as a tag in the field. Underneath, they are stored in braces, as `{email}` or `{external_id}`. Form fields carry a prefix when they are inserted, so the field you picked as `email` is stored as `{data_email}`. That is why a value copied from one integration into another may look different from what the picker showed you. You can type instead of picking, and mix the two in one field: ``` `Bearer {token} {first_name} {last_name}` ``` Every field with a picker also has a copy button, which is quicker when you need the same value in several places. #### The system parameters ##### Conversion - `origin_id` : the PalDock ID of the click or the lead. This is the identifier you use to attribute anything back to the affiliate - `send_id` : the PalDock ID of one delivery of a lead to one channel. Use it when you need the conversion tied to a specific channel in a pingtree - `conversion_id` : the PalDock ID of the sale or the prospect. One origin can have several - `external_id` : the advertiser’s own ID for the order - `affcid` : the affiliate’s own ID for the conversion - `action` : whether the conversion is being created or updated - `type` : the conversion type - `result` : the transaction result, such as pending, approved or rejected - `ip_address` : the IP address of the end user For what each identifier addresses and which one to send when, see [Conversion IDs explained](https://paldock.com/knowledge-base/conversion-ids-explained/). ##### Commission - `value` : the order value, used when the commission is a percentage of it - `commission` : the value the advertiser sent in their commission parameter - `adv_commission` : the final commission from the advertiser - `aff_commission` : the final commission for the affiliate - `commission_profit` : the difference between the two - `commission_id` : which commission applies, when several exist for the same type - `currency` : the currency of the offer - `price` : the price the advertiser bid, used in auction distribution ##### Offer - `offer_id` : the ID of the offer - `offer_name` : its name - `country` : its country ##### Advertiser - `advertiser_id` : the ID of the advertiser - `advertiser_name` : their nickname ##### Affiliate - `owner_id` : the ID of the affiliate - `owner_name` : their nickname ##### Integration - `integration_name` : the name of the integration - `channel_name` : the channel name from the pingtree - `channel_visible_name` : the name the customer sees - `postback_id` : the postback the flow belongs to - `redirect_url` : where the customer goes next ##### Time - `created_date` : when the conversion was created, written out - `timestamp` : the same moment as a Unix timestamp - `timestamp_sign` : the timestamp used when signing a request ##### Advertiser custom - `advs1` through `advs10`. Ten free slots for whatever a particular advertiser needs. Nothing is predefined, so decide what each one means and keep it consistent. ##### Affiliate custom - `affs1` through `affs10`. The same, for values belonging to the affiliate. ##### Execution - `step_run_id` : the ID of this run of this node. Advertisers often want it as a request ID, so a retry can be told apart from a new request - `random_uuid` : a fresh random identifier, generated for each request ##### Security - `digest` : the digest of the request body - `signature` : the signature of the request Both are produced by the [Signature](https://paldock.com/knowledge-base/signature/) setting on the HTTP node, and you place them in the headers yourself. ##### Cookies - `custom_cookie_ga` and `custom_cookie_ga_container_id` : Google identifiers - `custom_cookie_gcl_aw` : the Google Ads click identifier - `custom_cookie_fbp` and `custom_cookie_fbc` : Facebook identifiers Use these when forwarding conversions into advertising platforms, which need their own identifier to match the conversion to the click. ##### Where each one can be used This page is about what you can pick while building a scenario. Which parameters may be sent through a pixel, a postback, the Tracking API or an affiliate postback is a different question. See [Tracking parameters](https://paldock.com/knowledge-base/tracking-parameters/). --- ## Modifications ### List of modifications Modify Field transforms a value before it is stored or sent on. Reformatting a date, translating your vocabulary into the advertiser’s, deriving one field from another, or dropping a field from the request entirely. It is used in [Structures](https://paldock.com/knowledge-base/topics/structures/), in integrations, and in tracking. The operations are the same everywhere. ###### How a modification is built Each modification targets **one field** and is made of **steps**. A step has four parts: - **Source**, where the value comes from: this field, another field, or the result of an earlier step. - **Condition**, when the step should apply. Use *Always* when it should apply unconditionally. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). - **Operation**, what to do with the value. - **Parameter**, what the operation needs, if anything. Some take a pattern, some take a value, some take neither. ###### Steps run in order Steps are executed from top to bottom, and a later step can take an earlier one’s result as its source. That is how you build a value in stages rather than hunting for a single operation that does everything. ``` `1. {nin} first regex match ^\d{2} 2. step 1 prefix 19` ``` The condition on a step is checked against that step’s source value, as it is at that moment, not against what the field held when the modification started. ###### Two ways to use several steps **Chained**, where each step builds on the last. Good for a single transformation with stages. **Independent**, where several steps read the same original value and only one of them matches. Good for mapping a list of values, since each step has its own condition and only the matching one fires. If you need several genuinely separate transformations of the same input, it is usually cleaner to create a helper field for each, then combine them at the end. That keeps each chain short enough to follow. ###### The operations **Changing the type** - [to-int](https://paldock.com/knowledge-base/to-int/), [to-float](https://paldock.com/knowledge-base/to-float/), [to-bool](https://paldock.com/knowledge-base/to-bool/), [to-string](https://paldock.com/knowledge-base/to-string/) **Text** - [prefix](https://paldock.com/knowledge-base/prefix/) and [postfix](https://paldock.com/knowledge-base/postfix/) add something to the front or the back - [replace](https://paldock.com/knowledge-base/set-value/) set the value for a fixed one - [regex-replace](https://paldock.com/knowledge-base/regex-replace/) rewrites part of it by pattern - [first-regex-match](https://paldock.com/knowledge-base/first-regex-match/) pulls out the first match **Dates** - [format-date](https://paldock.com/knowledge-base/format-date/) changes how a date is written - [modify-date](https://paldock.com/knowledge-base/modify-date/) shifts it forwards or backwards - [unix](https://paldock.com/knowledge-base/unix/) turns it into a timestamp **Encoding** - [to-base64](https://paldock.com/knowledge-base/to-base64/) and [from-base64](https://paldock.com/knowledge-base/from-base64/) - [urlencode](https://paldock.com/knowledge-base/urlencode/) and [urldecode](https://paldock.com/knowledge-base/urldecode/) **Calculating** - [math](https://paldock.com/knowledge-base/math/) evaluates an expression, using `{value}` for the current value **Not sending** - [do-not-send](https://paldock.com/knowledge-base/do-not-send/) removes the field from the request ###### Getting it right Test with real data, not with what you expect the data to look like. Most Modify Field problems are not wrong logic, they are a value that arrived in a shape nobody planned for. Keep chains short. Three steps you can read beats one clever step you cannot. --- ### to-string The **to-string** operation turns a value into text. Use it when the other side expects a string and you are holding a number or a boolean. Some APIs are strict about it and reject `42` where they wanted `"42"`, especially when the value is an identifier rather than a quantity. It changes the type, not just the look of the value. The field becomes a string, so a JSON request carries `"42"` with quotation marks rather than `42`. ###### What comes out - **An integer** becomes its digits. `42` becomes `"42"`. - **A float** becomes its decimal notation. `1.25` becomes `"1.25"`. A float with nothing after the decimal point loses it, so `42.0` becomes `"42"`, not `"42.0"`. - **A string** is unchanged. - **true** becomes `"1"`. - **false** becomes an empty string, not `"false"` and not `"0"`. - **Null** becomes an empty string. - **A list** becomes the literal text `"Array"`, which is never what you want. - **An object** can only be converted if it knows how to represent itself as text. Otherwise it causes an error. ###### The catch The boolean is the one that catches people out. `true` becomes `"1"` and `false` becomes nothing at all, so a consent checkbox that was not ticked arrives as an empty field rather than as a “no”. If the advertiser expects the words `"true"` and `"false"`, or `"yes"` and `"no"`, do not use to-string. Use [set value](https://paldock.com/knowledge-base/set-value/) with a condition for each value, which gives you exactly the two strings they asked for. The same applies to null. An empty value stays empty, so if the field is required on their side you need [set value](https://paldock.com/knowledge-base/set-value/) to put something in it, or [do-not-send](https://paldock.com/knowledge-base/do-not-send/) to leave it out altogether. ###### When you actually need it Most values in a scenario are already strings, because that is how form fields arrive. You need to-string mainly after another operation changed the type, for example when [to-int](https://paldock.com/knowledge-base/to-int/) or [math](https://paldock.com/knowledge-base/math/) produced a number and the advertiser wants it quoted. Identifiers are the common case. A number that is really a code, such as a bank code or a product ID, should be a string, otherwise a leading zero disappears and `0100` becomes `100`. ###### Settings The operation takes no parameter. Set the source and the condition, choose to-string, and there is nothing else to fill in. ###### Reference The conversion follows PHP’s rules for casting to string. See [PHP: Converting to string](https://www.php.net/manual/en/language.types.string.php#language.types.string.casting). --- ### to-float The **to-float** operation turns a value into a decimal number. Use it when the other side expects a number and you are holding text. Form fields arrive as strings, so `1.25` typed into a form is the four characters `1.25`, not the number. Some APIs do not care, others reject the request. It changes the type, not just the look of the value. The field stops being a string and becomes a float, so a JSON request carries `1.25` rather than `"1.25"`, without quotation marks. ###### What comes out - **An integer** becomes its decimal equivalent. `42` becomes `42.0`. - **A numeric string** becomes the number it represents. `"1.25"` becomes `1.25`. - **A string that starts with digits** is read up to the first character that does not belong to a number. `"123abc"` becomes `123.0`. Nothing warns you that the rest was dropped. - **A string that does not start with a digit** becomes `0.0`. That covers `"abc123"`, `"N/A"` and anything else that is not a number. - **A boolean** becomes `1.0` for true and `0.0` for false. - **Null** becomes `0.0`. An empty field turns into a zero. - **A list or an object** cannot be converted and causes an error. ###### The catch Everything that is not a number becomes zero, silently. That matters when the value carries meaning. An income field left empty, or filled in as “none”, reaches the advertiser as `0`, which reads as “this person earns nothing” rather than “we do not know”. Some advertisers reject on that, others accept the lead and pay less for it. Watch out for the decimal comma as well. A form filled in as `1,25` is read only up to the comma, so it arrives as `1.0`. If your fields can contain commas, clean them up with [regex-replace](https://paldock.com/knowledge-base/regex-replace/) before converting. So decide what an empty or invalid value should be before you convert it. Put a condition on the step so it only runs on values that look like numbers, or handle the empty case separately with [set value](https://paldock.com/knowledge-base/set-value/) or [do-not-send](https://paldock.com/knowledge-base/do-not-send/). ###### Float or integer Use to-float for anything with a decimal part: amounts, rates, percentages. Use [to-int](https://paldock.com/knowledge-base/to-int/) for counts and whole numbers, and be aware it cuts the decimals off rather than rounding. If the advertiser works in whole units, to-int is usually what you want. If they expect `1200.00`, to-float is. ###### Settings The operation takes no parameter. Set the source and the condition, choose to-float, and there is nothing else to fill in. ###### Reference The conversion follows PHP’s rules for casting to float. See [PHP: Type Casting to Float](https://www.php.net/manual/en/language.types.float.php). --- ### to-bool The **to-bool** operation turns a value into true or false. Use it when the other side expects a real boolean rather than text, and when you want a clean yes or no to branch on later. It changes the type, not just the look of the value. A JSON request then carries `true` rather than `"true"` or `1`. ###### What comes out **The words true and false** are understood as what they say. The string `"true"` becomes true and the string `"false"` becomes false. This is a PalDock addition, not standard PHP behaviour, and it exists because those two strings are what forms and APIs actually send. Everything else follows PHP’s own rules, where a handful of values count as false and the rest count as true. **These become false:** - `false`, already a boolean - `0`, the integer zero - `0.0`, the float zero - `"0"`, the string containing a zero - `""`, an empty string - `[]`, an empty list - nothing at all **Everything else becomes true**, including: - any number other than zero, positive or negative - any non-empty string, including `"0.0"` and `"no"` - any list with something in it, even a list containing a zero - any object ###### The catch `"0"` is the only non-empty string that becomes false. Everything else with a character in it is true. That means a field filled in as `"no"`, `"off"` or `"nope"` becomes **true**, which is the opposite of what it says. If your values are words rather than flags, do not use to-bool. Use [set value](https://paldock.com/knowledge-base/set-value/) with a condition for each value, so you decide what maps to what. Watch the empty case too. A field nobody filled in becomes false, which reads as an explicit no rather than as a missing answer. When the difference matters, handle the empty case separately with [do-not-send](https://paldock.com/knowledge-base/do-not-send/). An empty list is false and a list holding a single zero is true, which surprises people the first time. ###### When you need it Consents and checkboxes are the usual reason. A form checkbox arrives as text and the advertiser wants a boolean. It is also worth doing before a condition that branches on the value, so you are comparing a real boolean rather than whatever text happened to arrive. ###### Settings The operation takes no parameter. Set the source and the condition, choose to-bool, and there is nothing else to fill in. ###### Reference Apart from the two words above, the conversion follows PHP’s rules for casting to boolean. See [PHP: Converting to boolean](https://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting). --- ### to-int The **to-int** operation turns a value into a whole number. Use it when the other side expects an integer and you are holding text, or when a value carries decimals that have no business being there. It changes the type, not just the look of the value. A JSON request then carries `42` rather than `"42"`, without quotation marks. ###### What comes out - **A numeric string** becomes the number it represents. `"42"` becomes `42`. - **A string with decimals** loses them. `"1.25"` becomes `1`. - **A float** loses them too. `1.25` becomes `1` and `-3.9` becomes `-3`. The decimals are cut off, not rounded, so `2.9` becomes `2` and never `3`. - **A string that starts with digits** is read up to the first character that does not belong to a number. `"123abc"` becomes `123`. - **A string that does not start with a digit** becomes `0`. That covers `"abc"`, `"N/A"` and anything else that is not a number. - **A boolean** becomes `1` for true and `0` for false. - **Null** becomes `0`. An empty field turns into a zero. - **A list or an object** cannot be converted and causes an error. ###### The catch Two things bite here, and both are silent. **Decimals disappear rather than round.** An amount of `1999.90` becomes `1999`, and a rate of `0.95` becomes `0`. If the value is money and the advertiser works in whole units, that is what you want. If it is a rate or a percentage, to-int destroys it, and [to-float](https://paldock.com/knowledge-base/to-float/) is the right operation. **Anything that is not a number becomes zero.** An income field left empty, or filled in as “none”, reaches the advertiser as `0`, which reads as “this person earns nothing” rather than “we do not know”. Some advertisers reject on that, others accept the lead and pay less for it. Watch the decimal comma as well. A form filled in as `1,25` is read only up to the comma, so it arrives as `1`. If your fields can contain commas, clean them up with [regex-replace](https://paldock.com/knowledge-base/regex-replace/) first. So decide what an empty or invalid value should be before you convert it. Put a condition on the step so it only runs on values that look like numbers, or handle the empty case separately with [set value](https://paldock.com/knowledge-base/set-value/) or [do-not-send](https://paldock.com/knowledge-base/do-not-send/). ###### Careful with codes A number that is really an identifier should stay a string. Bank codes, product codes and postal codes often start with a zero, and to-int throws it away: `0100` becomes `100`. Use to-int for quantities and amounts, not for anything you would never do arithmetic with. ###### Settings The operation takes no parameter. Set the source and the condition, choose to-int, and there is nothing else to fill in. ###### Reference The conversion follows PHP’s rules for casting to integer. See [PHP: Converting to integer](https://www.php.net/manual/en/language.types.integer.php#language.types.integer.casting). --- ### set value The **set** operation replaces the value with one you choose. It does not look at what was there before. When the step runs, whatever the field held is discarded and your value takes its place. ###### How it works You type the value in the operation settings. It can be: - a fixed word, such as `APPROVED` - a number, such as `0` - a value built from other fields, using references in braces, such as `{first_name} {last_name}` Then the condition decides when it happens. This is the important half. ###### The condition is what makes it useful On its own, set is blunt: it overwrites everything, every time. Paired with a condition, it becomes the way you translate your values into somebody else’s. ``` `Field: {income_type} equals full-time → employed equals self-employed → self-employed equals pension → pensioner` ``` Each line is a set with its own condition, all inside one Modify Field node. Only the matching line fires, and the rest leave the value alone. That is the standard way to map a list of values, and it is why set is by far the most used operation in PalDock. ###### The other common uses - **Filling in a required field that is empty.** Some advertisers reject a request outright when a field is missing, even one they do not care about. A set with the condition *is empty* puts a placeholder in. - **Capping a number.** The advertiser lends up to 20 000 and your form allows more. A set with the condition *is greater than 20 000* and the value `20000` sends the highest amount they can work with, instead of one they will refuse. - **Normalising several inputs into one.** Three different statuses that all mean the same thing, mapped onto a single value the advertiser understands. ###### The catch - **With no condition, everything is replaced.** Set with the condition *Always* wipes the field for every lead, which is occasionally what you want and usually not. If you meant to change only some values, the condition is not optional. - **Set does not search inside the value.** It swaps the whole thing. To change part of a value, or to match a pattern rather than an exact value, use [regex-replace](https://paldock.com/knowledge-base/regex-replace/). - **One condition can cover several values.** Rather than writing three lines for three statuses that all map to the same output, use the *Regex match* operator with `approved|accepted|ok`. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). ###### Settings The operation takes one parameter: the value to set. Everything else is the source and the condition. --- ### math The **math** operation calculates a value from a formula. You write the expression, PalDock fills in the field values and works out the result. This operation was previously called **match**, which was a typo. ###### How it works Write the formula in the parameter. Reference field values in braces: - **`{value}`** is the value the step is working with. - **`{field_name}`** is any other field in the scenario. ``` `Formula: {value} * 2 Input: 30 Result: 60` ``` ``` `Formula: {price} / 100 Input: 19900 Result: 199` ``` You can combine several fields in one formula, for example `{length} * {width}`. ###### What you can write **Operators** - `+` addition - `-` subtraction - `*` multiplication - `/` division - `^` exponentiation - `( )` parentheses, to control what is calculated first **Functions** - `sqrt(x)` square root - `abs(x)` absolute value - `round(x)` round to the nearest whole number - `floor(x)` round down - `ceil(x)` round up - `log(x)` natural logarithm - `sin(x)` and `cos(x)` ###### When the calculation fails If the formula cannot be worked out, **the field keeps its original value**. Nothing is written to the log, no error is raised, and the flow carries on. That makes a broken formula genuinely hard to spot, because the value that arrives at the advertiser looks plausible, it is just the number from before the calculation. A field of `19900` that should have become `199` still reads as an amount. The usual causes are an empty input field, a value that is text rather than a number, and a reference to a field that does not exist in this scenario, which leaves the braces unreplaced. So check the input before you calculate. Convert with [to-float](https://paldock.com/knowledge-base/to-float/) or [to-int](https://paldock.com/knowledge-base/to-int/) first, and put a condition on the step so it only runs when the field actually holds a number. ###### Rounding Division produces decimals, and most advertisers will not thank you for `66.66666666666667`. Wrap the formula in `round()`, `floor()` or `ceil()` depending on what the value means. Rounding down is the safe choice for anything the advertiser will treat as a limit, since rounding up can push you over it. ###### Settings The operation takes one parameter: the formula. Everything else is the source and the condition. ###### Reference Calculations are performed by [chriskonnertz/string-calc](https://github.com/chriskonnertz/string-calc), which is where the full list of supported functions lives. --- ### unix The **unix** operation turns a date into a Unix timestamp, the number of seconds since 1 January 1970. Use it when an API expects a number rather than a written date, and when you want to compare two dates by size rather than by text. ###### How it works Give it a date and you get a number back. ``` `2024-12-25 → 1735084800 2025-03-01 12:00 → 1740830400 01/01/1970 → 0` ``` The timestamp is always counted in UTC. ###### When it cannot read the date **The field keeps its original value.** Nothing is logged and no error is raised, so a date the operation could not understand travels on to the advertiser exactly as it arrived. That is worth planning for, because the failure looks like nothing happened. If the advertiser expects a number and receives `25.12.2024`, they will reject the lead and the reason will not mention dates at all. Put a condition on the step, or check the value afterwards, rather than assuming the conversion worked. ###### Formats it understands Anything written the international way is safe: `2024-12-25` or `2024-12-25 14:30:00`. Formats with slashes are read the American way, so `01/02/2025` is the first of February, not the second of January. If your dates arrive in a local format, reformat them first with [format-date](https://paldock.com/knowledge-base/format-date/) rather than hoping they are read correctly. A date written as `25.12.2024` is not understood at all and comes back unchanged. ###### Working with other date operations The three date operations are built to be chained: - **[modify-date](https://paldock.com/knowledge-base/modify-date/)** shifts a date forwards or backwards - **[format-date](https://paldock.com/knowledge-base/format-date/)** writes it a different way - **unix** turns it into a number Shift first, then convert. A step that adds thirty days and a step that turns the result into a timestamp is the usual way to send an expiry date as a number. ###### Settings The operation takes no parameter. Set the source and the condition, choose unix, and there is nothing else to fill in. ###### Reference Dates are read with PHP’s `strtotime`. See [PHP: strtotime](https://www.php.net/manual/en/function.strtotime.php) for the full list of formats it accepts. --- ### prefix The **prefix** operation puts a value in front of the existing one. The original is kept, it just gains something at the start. ###### How it works You type the prefix in the operation settings and it is placed at the beginning of the value. ``` `Value: 12345 Prefix: ID- Result: ID-12345 Value: 797992279 Prefix: +420 Result: +420797992279` ``` Nothing else changes. The operation does not look at what is already there. ###### Mind the space The prefix is joined to the value exactly as you typed it, so if you need a space between them, type it. `Bearer` with a trailing space gives `Bearer eyJhbGci…`, which is what an authorisation header needs. `Bearer` without one gives `BearereyJhbGci…`, which the other side rejects without saying why. Trailing spaces are easy to lose when copying from documentation, so this is worth checking when a token that looks right keeps being refused. ###### Use a condition, or it happens every time The operation does not check whether the prefix is already there. Run it on a phone number that already starts with `+420` and you get `+420+420797992279`. That matters whenever the data comes from several sources, or when the same field is filled in by hand. Set the condition so the step only runs when the prefix is missing, for example *does not start with* the prefix, or *is less than* a certain length for a phone number. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). ###### The common uses - **Authorisation headers.** Adding `Bearer` to a token, or `Basic` to encoded credentials. This is by far the most frequent one. See [HTTP request](https://paldock.com/knowledge-base/http-node/). - **Country codes on phone numbers.** Your form collects the local number, the advertiser wants it international. - **Identifiers.** Advertisers who expect their own IDs to arrive tagged, such as `ID-` or a partner code. ###### The other direction To add something at the end instead, use [postfix](https://paldock.com/knowledge-base/postfix/). To build a value from several fields at once, write them together in the field, as `{first_name} {last_name}`, rather than chaining prefixes. ###### Settings The operation takes one parameter: the text to put in front. Everything else is the source and the condition. --- ### postfix The **postfix** operation puts a value at the end of the existing one. The original is kept, it just gains something after it. ###### How it works You type the postfix in the operation settings and it is placed at the end of the value. ``` `Value: 100 Postfix: USD Result: 100USD Value: 50 Postfix: kg Result: 50kg Value: user Postfix: -01 Result: user-01` ``` Nothing else changes. The operation does not look at what is already there. ###### Mind the space The postfix is joined to the value exactly as you typed it, so if you want `100 USD` rather than `100USD`, the space goes at the start of the postfix. Whether it belongs there depends on the other side. Check their documentation or an example payload rather than guessing, because both forms look equally reasonable in the editor. ###### It stops being a number Adding text to a number makes the whole thing text. `100` was a number, `100USD` is a string. That is fine when the advertiser wants it that way, but it means any calculation has to happen first. Do the [math](https://paldock.com/knowledge-base/math/) and the rounding, then add the postfix as the last step. It also means you should think twice before doing it at all. Most APIs want the amount and the currency as two separate fields, and an amount arriving as `100USD` is a common reason a request is rejected. Add a unit only when their documentation actually asks for it. ###### Use a condition, or it happens every time The operation does not check whether the postfix is already there. Run it twice, or on data that already carries the unit, and you get `100USDUSD`. Set the condition so the step only runs when the postfix is missing, for example *does not end with* it. See [Condition Operators and Field value](https://paldock.com/knowledge-base/condition-operators-and-field-value/). The same applies when the field can hold values from different sources, where some already carry the unit and some do not. ###### The common uses - **Currencies and units,** where the advertiser expects them joined to the value: `100USD`, `50kg`, `3.5m`. - **Identifiers and labels,** such as `-01`, `-A` or `-TEST`, for values you want to tell apart later. Keep whatever you choose consistent across the workspace. `EUR` in one integration and `€` in another turns into a reporting problem long before anyone notices. ###### The other direction To add something at the beginning instead, use [prefix](https://paldock.com/knowledge-base/prefix/). To build a value from several fields at once, write them together in the field, as `{amount} {currency}`, rather than chaining postfixes. ###### Settings The operation takes one parameter: the text to put at the end. Everything else is the source and the condition. --- ### first-regex-match The **first-regex-match** operation pulls a piece out of a value using a pattern. It finds the first thing that matches and returns just that. Use it when the value you need is buried in text: an order number in a sentence, a code inside an identifier, digits inside something formatted. ###### How it works You write a regular expression in the parameter. The operation searches the value and returns the first match. ``` `Pattern: \d+ Value: Order n. 12345 Result: 12345 Pattern: [a-z]+ Value: 123 ABC xyz Result: xyz Pattern: ^\d{2} Value: 5501150325 Result: 55` ``` The whole match is returned, not a captured group. Brackets in your pattern help you describe what to look for, but the result is always the entire matched section. ###### When nothing matches **The result is an empty string.** Not the original value, and not an error. The field ends up blank. That is the behaviour to plan around, because an empty field usually travels on quietly. The advertiser receives nothing where they expected an order number, and the rejection that follows will not mention the pattern. The same thing happens when the pattern itself is invalid. A stray bracket or an unescaped character gives you an empty result rather than a complaint, so a broken pattern looks exactly like a value that did not match. Check for the empty case afterwards. A condition on the connection leaving the node, or a following step with the condition *is empty*, is enough to tell the two situations apart from a lead that simply had nothing to find. ###### Only the first one If the value contains several matches, you get the first. There is no way to ask for the second, or for all of them. When you need more than one piece out of the same value, extract each into its own field, each with its own pattern anchored to a different position. ###### Test the pattern first Write the pattern somewhere you can see it working before you paste it into PalDock. [regex101.com](https://regex101.com/) shows you what matches and why, which the editor cannot. This matters more than usual here, because of the silent failure. A pattern that is subtly wrong produces the same empty string as no pattern at all. If you generate the pattern with an AI tool, test it anyway. They are good at plausible patterns and less good at correct ones, and the failure mode here gives you nothing to notice. ###### Changing rather than extracting first-regex-match takes a piece out and throws the rest away. To keep the value and rewrite part of it, use [regex-replace](https://paldock.com/knowledge-base/regex-replace/), which is where capturing groups do what you would expect. ###### Reference Patterns follow PHP’s PCRE syntax. See [PHP: Pattern Syntax](https://www.php.net/manual/en/reference.pcre.pattern.syntax.php). --- ### do-not-send The **do-not-send** operation removes a value instead of changing it. The field is emptied, and with the right setting on the request, it is left out altogether. Use it when an empty value is worse than no value, and when something in your data should never reach the other side. ###### How it works There is no parameter. The condition does all the work. ``` `Condition: is empty → the field is dropped Condition: equals test → dropped only when the value is exactly "test" Condition: always → the field is never sent` ``` When the condition is not met, the field carries on as normal with its value untouched. ###### It works together with the request settings do-not-send clears the value. Whether the field then disappears from the request or arrives as an empty one is decided on the [HTTP request](https://paldock.com/knowledge-base/http-node/) node, by the **Skip field when** setting. If you want the field genuinely gone, set that to skip on null. Without it the advertiser may receive the key with nothing in it, which for some APIs is the very thing you were trying to avoid. This is worth checking before you rely on the operation. Two integrations built the same way can behave differently here, purely because of a setting on the request rather than on the field. ###### When to reach for it **Empty optional fields.** Some APIs are stricter about an empty value than about a missing one, and will reject a request carrying a blank field they never needed. **Test data.** Keeping a placeholder from reaching a production endpoint. **Values that are only sometimes relevant.** A company number that applies to the self-employed and to nobody else. Send it when it means something, drop it when it does not. ###### Careful with required fields Dropping a field the advertiser requires produces a rejection, and their error message will usually name the field rather than explain that it was missing. Before setting this up, check their documentation for what is genuinely mandatory. Where a field is required but your value is empty, [set](https://paldock.com/knowledge-base/set-value/) a placeholder instead of dropping it. ###### Finding out what was dropped A suppressed field leaves no trace in the payload, so a request that looks wrong gives you nothing to work from. The run log shows what the node received and returned, and `{request_body}` on the HTTP node shows what actually went out. Compare the two and the missing field is obvious. See [HTTP request](https://paldock.com/knowledge-base/http-node/). --- ### format-date The **format-date** operation writes a date a different way. The date itself does not change, only how it is written. Use it when the advertiser wants a format your data does not use. ###### How it works You give it a format pattern and it rewrites the value to match. ``` `Value: 2024-02-21 Pattern: d.m.Y Result: 21.02.2024 Value: 2024-02-21 15:30:00 Pattern: Y-m-d H:i Result: 2024-02-21 15:30 Value: 2024-02-21 15:30:00 Pattern: Y-m-d Result: 2024-02-21` ``` That last one is how you drop the time from a date that carries it. ###### Patterns worth knowing - `Y-m-d` gives `2024-02-21`, the international format - `d.m.Y` gives `21.02.2024`, common across Europe - `m/d/Y` gives `02/21/2024`, the American one - `Y-m-d H:i:s` gives `2024-02-21 15:30:00`, a full timestamp - `l, j F Y` gives `Wednesday, 21 February 2024`, written out The letters are case sensitive. `Y` is a four-digit year and `y` is two, `m` is a zero-padded month and `n` is not. ###### An unreadable date stops the flow If the value cannot be read as a date, the node fails with an error and the branch stops there. This is different from [unix](https://paldock.com/knowledge-base/unix/), which quietly hands back the original value. Here you find out, which is better, but it means an empty or malformed date field takes the run down with it. So put a condition on the step. Running it only when the field is not empty avoids the most common cause by itself. ###### Starting from a timestamp A Unix timestamp is a number, not a date, and reading it as one gives nothing useful. Put an `@` in front of it first, so `1735084800` becomes `@1735084800`, which is understood as a timestamp. Use [prefix](https://paldock.com/knowledge-base/prefix/) for that, then format-date. The `@` belongs in front of the value, not in front of the pattern. ###### Time zones format-date rewrites the text and nothing else. It does not shift the date into another time zone, so a date recorded in UTC stays UTC no matter how you write it. If the advertiser needs a different zone, that is a separate problem and format-date will not solve it. ###### Working with the other date operations - **[modify-date](https://paldock.com/knowledge-base/modify-date/)** shifts a date forwards or backwards - **[unix](https://paldock.com/knowledge-base/unix/)** turns it into a timestamp - **format-date** writes it a different way Shift first, format last. A step that adds thirty days followed by a step that formats the result is the usual way to send an expiry date. ###### Reference Patterns follow PHP’s date formatting. See [PHP: DateTime::format](https://www.php.net/manual/en/datetime.format.php) for the full list of letters. --- ### modify-date The **modify-date** operation shifts a date forwards or backwards. You describe the change in words and the operation works out the new date. The result always comes back in ISO 8601 format, such as `2024-02-22T15:30:00+00:00`, whatever format went in. ###### How it works You write the shift in the parameter, in plain English. ``` `Value: 2024-02-21 15:30:00 Change: +1 day Result: 2024-02-22T15:30:00+00:00 Value: 2024-02-21 Change: -2 months Result: 2023-12-21T00:00:00+00:00 Value: 2024-02-21 Change: next Monday Result: 2024-02-26T00:00:00+00:00` ``` Common forms are `+30 days`, `-2 hours`, `+1 month`, `next Monday`, `last day of this month`. PHP understands a lot more than that, and the reference at the bottom has the full list. ###### Using another field in the shift The change does not have to be fixed. Put a field reference in braces and it is filled in before the date is worked out. ``` `Change: +{period} days` ``` That is how you build an expiry date from a term the customer chose, rather than writing a separate step for every possible length. ###### The output format is not optional The result is always ISO 8601. If the advertiser wants something else, follow this step with [format-date](https://paldock.com/knowledge-base/format-date/). That is the usual pair: shift the date, then write it the way they asked for. ###### An unreadable date stops the flow If the value cannot be read as a date, the node fails with an error and the branch stops there. Put a condition on the step so it only runs when the field holds something. An empty date field is the most common cause by a distance. ###### Careful with months Adding a month is not the same as adding thirty days, and the difference shows up at the end of a month. `31 January` plus one month lands in March, because February has no 31st and the overflow carries forward. If you mean a fixed number of days, say days. Use months only when the advertiser’s rule is genuinely expressed in months. ###### Working with the other date operations - **modify-date** shifts a date - **[format-date](https://paldock.com/knowledge-base/format-date/)** writes it a different way - **[unix](https://paldock.com/knowledge-base/unix/)** turns it into a number Shift first, then convert or format. Doing it the other way round usually means the shift runs on text that is no longer a date. ###### Reference See [PHP: DateTime::modify](https://www.php.net/manual/en/datetime.modify.php) and [Relative Date and Time Formats](https://www.php.net/manual/en/datetime.formats.relative.php) for everything the change accepts. --- ### to-base64 The **to-base64** operation encodes a value into Base64, a way of writing anything as plain ASCII text. You need it when an API asks for it, and almost the only time it asks is for authentication. ###### How it works ``` `Value: hello Result: aGVsbG8= Value: 12345 Result: MTIzNDU= Value: {"id":1} Result: eyJpZCI6MX0=` ``` An empty value gives an empty result. ###### Basic authentication This is the common use, and it takes three steps because the header carries one encoded string rather than two values. - A **[Set](https://paldock.com/knowledge-base/set/)** node joins the credentials with a colon between them, for example `{client_id}:{client_secret}`, into a field of its own. - A **Modify Field** step runs to-base64 on it. - The header on the request reads `Authorization: Basic {auth}`. The prefix is `Basic `, with a trailing space. Not `Bearer `, which goes in front of a token that is already usable as it stands and never gets encoded. Mixing the two up is the most frequent reason an authentication header is refused. See [prefix](https://paldock.com/knowledge-base/prefix/) and [HTTP request](https://paldock.com/knowledge-base/http-node/). ###### It is not encryption Base64 hides nothing. Anyone who sees the encoded string can decode it in a second, and [from-base64](https://paldock.com/knowledge-base/from-base64/) will do it for you. It exists to make arbitrary data safe to put in a text field, not to protect it. Treat an encoded secret exactly as carefully as you would treat the secret itself. ###### When not to use it Only encode when the other side specifically asks for it. Sending Base64 to an API that expected plain text gives you a rejection with an unhelpful message, because to them the value simply looks wrong. Bear in mind it also makes the data about a third larger, which matters if you are ever moving something big. ###### The other direction To decode, use [from-base64](https://paldock.com/knowledge-base/from-base64/). ###### Reference See [PHP: base64_encode](https://www.php.net/manual/en/function.base64-encode.php). --- ### from-base64 The **from-base64** operation decodes a Base64 value back into what it was. It is the reverse of [to-base64](https://paldock.com/knowledge-base/to-base64/). ###### How it works ``` `Value: aGVsbG8= Result: hello Value: MTIzNDU= Result: 12345 Value: eyJpZCI6MX0= Result: {"id":1}` ``` ###### Invalid input does not fail This is the one to watch. Decoding something that is not Base64 does not produce an error and does not leave the value alone. Characters the decoder does not recognise are skipped and the rest is decoded anyway, so you get a shorter, meaningless string. Nothing about that result announces itself as wrong. It is not empty, so a check for an empty value will not catch it, and it travels on to the advertiser looking like an ordinary value. So only decode where you know the value is encoded. If a response sometimes carries Base64 and sometimes plain text, put a condition on the step rather than decoding everything and hoping. ###### When you need it **Reading a response that arrives encoded.** Some APIs return a payload as Base64 and you want the contents. **Checking what is inside a token.** The parts of a JWT are Base64, so decoding one shows you what it claims. **Recovering something you encoded earlier**, when a later step in the same flow needs the original. ###### Binary data Base64 can hold anything, including data that is not text. Decoding a file or an image into a field gives you bytes that make no sense as characters and will usually break whatever you send them to. Decode into a text field only when you know the original was text. ###### Reference See [PHP: base64_decode](https://www.php.net/manual/en/function.base64-decode.php). --- ### regex-replace The **regex-replace** operation rewrites part of a value using a pattern. You say what to find and what to put in its place, and every match is replaced. Use it when you need to change a value rather than extract from it: inserting separators, stripping characters, reshaping an identifier. ###### How it works Two parameters. **Pattern** is the regular expression that finds what should be replaced. Write it without slashes around it, PalDock adds those. **Output** is what replaces each match. Reference the pieces the pattern captured: - `$1`, `$2` and so on insert the first, second and further capturing groups - `$0` inserts the whole match ``` `Pattern: (\d{6})(\d{4}) Output: $1/$2 Value: 1234123456 Result: 123412/3456` ``` The pattern makes two groups, six digits and four digits, and the output puts them back with a slash between them. Groups are numbered from left to right starting at one. ###### What happens when it does not work - **A pattern that matches nothing** leaves the value exactly as it was. This is the safe case. - **A pattern that is not valid** empties the field. A missing bracket, a stray modifier, and the result is nothing at all. Those two look nothing alike in the data, which is useful: an unchanged value means your pattern was fine but did not apply, an empty one means the pattern itself is broken. ###### Writing the replacement Prefer `$1` over `\1`. Both work, but `$1` is the recommended form and reads better. Use `${1}` when a digit follows the group number. `${1}1` is group one followed by the digit one, while `$11` is read as group eleven. To output a literal dollar sign followed by a number, escape it as `\$1`. ###### Writing the pattern Write the raw expression with no slashes around it. If the value itself contains a slash, escape it inside the pattern. For flags, put them inline at the start: `(?i)` for case insensitive, `(?m)` for multiline, `(?s)` to let the dot match newlines, `(?u)` for UTF-8. Watch out for greedy matching. `.*` takes as much as it can, which is usually more than you meant. Use `.*?` when you want the shortest match, or describe the content precisely instead of using a wildcard at all. Named groups work in the pattern, as `(?P\d{2})`, but the replacement still refers to them by number. ###### Test the pattern first Try it in [regex101.com](https://regex101.com/) before pasting it in. You can see what matches, check the group numbering, and confirm the replacement does what you think. This applies double if you had an AI write the pattern. They produce plausible expressions readily and correct ones less reliably, and here a wrong one either does nothing or empties the field. ###### Extracting rather than rewriting regex-replace keeps the value and changes part of it. To pull a piece out and discard the rest, use [first-regex-match](https://paldock.com/knowledge-base/first-regex-match/). ###### Reference See [PHP: preg_replace](https://www.php.net/manual/en/function.preg-replace.php) and [Pattern Modifiers](https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php). --- ### urlencode The **urlencode** operation makes a value safe to put in a URL. Characters that would break the URL, or be read as part of its structure, are turned into percent codes. ###### How it works ``` `Value: hello world Result: hello+world Value: info@example.com Result: info%40example.com Value: +420797992279 Result: %2B420797992279 Value: ahoj světe & go Result: ahoj+sv%C4%9Bte+%26+go` ``` The rules are simple: spaces become `+`, letters, digits and `-` `_` `.` `~` stay as they are, and everything else becomes `%` followed by two hex digits. ###### Spaces become plus, not %20 Both forms are valid in a query string and most systems accept either. Some do not, and a value that arrives with a literal `+` where a space should be is the usual symptom. If the other side needs `%20`, this operation is not the one you want, and it will need to be handled differently. Check an example from their documentation before assuming. ###### Where the plus sign bites A phone number written as `+420797992279` encodes to `%2B420797992279`, which is correct. Left unencoded in a URL, that same `+` is read as a space, and the number arrives as `420797992279`. This is the single most common reason a phone number breaks in a query parameter, and it is invisible until you look at what actually arrived. ###### When you need it **Only for values going into a URL**, meaning a query parameter or a redirect link you are building yourself. You do not need it for values in a JSON body, and encoding them there sends the advertiser percent codes instead of text. You do not usually need it for the query fields on an [HTTP request](https://paldock.com/knowledge-base/http-node/) node either, since those are encoded when the request is built. Encoding twice turns `%40` into `%2540`, which nobody wants. So reach for it when you are assembling a URL as a value, not when you are filling in a request. ###### The other direction To decode, use [urldecode](https://paldock.com/knowledge-base/urldecode/). ###### Reference See [PHP: urlencode](https://www.php.net/manual/en/function.urlencode.php) and [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986). --- ### urldecode The **urldecode** operation turns a URL-encoded value back into ordinary text. It is the reverse of [urlencode](https://paldock.com/knowledge-base/urlencode/). ###### How it works ``` `Value: hello+world Result: hello world Value: info%40firma.cz Result: info@firma.cz Value: %2B420797992279 Result: +420797992279 Value: ahoj+sv%C4%9Bte+%26 Result: ahoj světe &` ``` Percent codes become the characters they stand for, `+` becomes a space, and anything that was not encoded is left alone. ###### Decoding something that was not encoded Because unencoded characters pass through untouched, running this on ordinary text mostly does nothing. Mostly. The exception is the plus sign. A value that genuinely contains one, such as a phone number written `+420797992279`, comes out as `420797992279` with a leading space. The number is now wrong and nothing about it looks unusual. So decode only where you know the value arrived encoded. If a field is sometimes encoded and sometimes not, put a condition on the step, for example only decoding when the value contains a `%`. ###### When you need it **Values arriving in a query string.** An incoming postback or webhook that carries a name or an email in the URL will have them encoded. **Reading a value back out of a link.** A redirect URL from an advertiser often has parameters inside it, and those are encoded. **Checking what a value really is** when something looks wrong and you suspect it was encoded twice. A value showing `%2540` was encoded once too often, and decoding it once gives you `%40`. ###### Malformed input A percent sign that is not followed by two valid hex digits is left as it is rather than causing an error. That means a half-encoded value decodes partially and quietly, so the result may be neither the original nor an obvious failure. ###### Reference See [PHP: urldecode](https://www.php.net/manual/en/function.urldecode.php) and [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986). --- # Settings ## About settings Settings is where you configure the workspace itself: how it looks, what it allows, how it measures, and who can get into it. It is not the same thing as your personal account. Your name, email, password and billing details belong to your PalDock account and follow you into every workspace you have access to. See [One Account, Multiple Workspaces](https://paldock.com/knowledge-base/one-account-multiple-workspaces/). Settings is divided into six areas: - **General** covers branding, defaults for new partners and advertisers, what the workspace permits, and minimum payouts. - **Users** is who has access and what they are allowed to do. - **Tracking** covers domains, conversion types, the cookie window, lead uniqueness and what is excluded from measurement. - **Labels** are the tags and categories you use to organise things across the workspace. - **Fields** are the fields available to every structure in the workspace. - **Billing and documents** is invoicing and the paperwork behind it. Everything here applies to one workspace. If you run several, each has its own settings. ##### General ###### Customization How the workspace presents itself to partners and advertisers. - **Name** is what people see. **Slug** is the short form used in URLs. - **Workspace domain** is the address the portal runs on. - **Logo**, **dark mode logo** and **favicon**. Upload the dark version too, otherwise a light logo disappears against a dark background. - **Workspace template** sets the default look and the terminology for your vertical, such as lending. ###### Default settings Values applied to everything created in the workspace unless something overrides them. - **Default country** and **default currency** are what a new offer, partner or advertiser starts with. - **Affiliate billing** decides whether billing follows the workspace settings or is handled per partner. - **New partners** and **new advertisers** decide what happens when somebody registers: approve them automatically, or hold them for manual approval. Automatic is convenient and means anyone who finds your registration form is in. - **Show my affiliate program in the catalog** lists your program publicly so affiliates can approach you. Leave it off if you only work with partners you recruit yourself. - **Categories** decide where your program appears in that catalog. ###### Options - What the workspace permits. These are the settings that change what other people can do, so they are worth going through deliberately rather than leaving at their defaults. - **Allowed sources** limits how leads may reach you: a link, an iframe, or the API. Turning one off closes that route for everyone in the workspace. - **Allowed form edits** decides how far a partner may customise an embedded form. Colours and texts are the usual choices. The more you allow, the further a form can drift from what you designed. - **Lead sharing with partners** decides whether partners can see lead data, rather than only counts and payouts. - **Custom pingtrees** decides whether partners may build their own distribution rather than using yours. - **Custom tokens** decides whether partners may define their own parameters. - **Lead anonymisation** removes personal data from leads after a set time, counted from when the lead arrived. The default of 86 400 seconds is one day. This is the setting people reach for when a retention rule requires it, so check what your obligations actually are before changing it, in either direction. ###### Minimum payouts The smallest amount a partner has to reach before they can be paid, set per currency. Set one for every currency you actually pay in. A partner earning in a currency with no minimum has nothing to reach, which is rarely what anyone intended. ---