Pay For Performance (P4P) Job Posting
The LinkedIn's Pay For Performance (P4P) Job Posting enables posting of P4P jobs to LinkedIn from external solutions. P4P Job Posting is an extension of LinkedIn's Job Posting, and the job posting API request format is a superset of the format used for Promoted Jobs unless you are ingesting jobs via XML feed.
What To Expect
Important
Please read below thoroughly to understand the right next steps for your use case.
Implementation requirements vary depending on your offering and objectives:
- For any partners, to view your P4P jobs and budgets, you will need to configure the P4P Reports API. This API has a similar usage to Check Job Posting Statuses API which you can also check the status of the posted jobs with
externalJobPostingId
orpartnerJobCode
, if applicable. You can find sample API requests from the "Try in Postman" collection above. You will need to join the LinkedIn Workspace and be approved to access it. Each partner will be requested to create a LinkedIn Developer Application to be the master or parent key of any LinkedIn Talent Solutions API integrations. With this key, you will be able to generate child applications with the Provisioning API to represent each client configuration within your partnership ecosystem. Please find a diagram below for a visual aid. To self-provision and activate each child app to be ready for posting or managing jobs or campaigns, you will need to call Provision Customer Hiring Contracts API. - If you are a Job Distributor (JD) or ATS partner who allows customers to buy individual job advertisements on Job Boards, you will need to add
PayForPerformanceTotalBudget
to your job posting request as in the Job Posting Schema with Pay For Performance (P4P) Extension. To learn more about how to post P4P jobs via API, please proceed to the section Sample Request for P4P Job Posting API below. Note that P4P Job Campaign API is NOT used to manage individual job advertisements. - If you are a Recruitment Advertising Agency (RAA) partner that posts jobs on behalf of customers via Campaigns, you will need to understand the P4P Job Campaign API to set up. A
campaign
is a series of goals that allow the sharing a single theme for more organized job management and related communications. It lets you group and strategize your customers' jobs and their budgets. Regardless of whether you post jobs via XML or API, campaign creation and maintenance should be handled by this API. If you post jobs via XML feed, please move on to the P4P Job Campaign API for your next step, and skip the Sample Request for P4P Job Posting API below. Keep in mind that, in your XML feed, you will need to add up to 3 fields to support P4P-specific job management as you can find them under Pay For Performance (P4P) Jobs XML Extension Schema. If you post jobs via API, please proceed to the section Sample Request for P4P Job Posting API below with the extended schema. Make sure that thecontract
andexpireAt
fields work differently in RAA than the rest of the Job Posting products as described in the Sample Request Body for Job CreationNote
.
To help understand here is a brief diagram of what the Parent-Child Developer Application relationship is like and how to activate your customer per product:
Once development is ready for certification, please contact your Partner Solutions Engineer and Business Development contacts to setup a meeting.
Sample Request for P4P Job Posting API
In order to post a job as P4P, you need to provide listingType
field value as PREMIUM
with the right contract.
Note
- Only selective partners have the permission to post P4P jobs. If your developer application does not support posting P4P jobs, please reach out to LinkedIn's business development point of contact, if interested.
- If you'd like to know more about Simple Job Postings (SJP) API, please visit Job Posting Overview.
curl --location --request POST 'https://api.linkedin.com/v2/simpleJobPostings' \
--header 'Authorization: Bearer {access_token}' \
--header 'x-restli-method: batch_create'
Note
- You should generate the {access_token} from the Child Developer Application (via Provisioning API) that represents each Client account of yours.
Sample Request Body for Job Creation
Standard Job Creation
{
"elements":[
{
"integrationContext": "urn:li:company:{your_company_id}",
"contract": "urn:li:contract:{your_contract_id}",
"companyApplyUrl": "https://careers.yourcompany.com",
"externalJobPostingId": "PromotedJobPostingG1TC1",
"companyJobCode": "ATS-SourceID_or_externalJobPostingId_of_this_job",
"posterEmail": "poster@linkedin.com",
"jobPostingOperationType": "CREATE",
"title": "Promoted Job Posting G1 TC1",
"description": "<b>Objective of the Position</b><br/> <ul> <li>To develop digital content plan, manage and monitor different content executions for social and online platforms to maximize the communication effectiveness and impact</li> <li>To manage, monitor and keep optimizing the performance of social platforms of MB and AMG</li> <li>To monitor and manage internet word of mouth to keep the health of brand and product image</li></ul>",
"listedAt": 1513756352000,
"location":"San Francisco, CA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "275.00"
}
},
"listingType": "PREMIUM"
}
]
}
RAA Job Creation
{
"elements":[
{
"integrationContext": "urn:li:company:{your_company_id}",
"companyApplyUrl": "https://careers.yourcompany.com",
"externalJobPostingId": "PromotedJobPostingG1TC1",
"companyJobCode": "ATS-SourceID_or_externalJobPostingId_of_this_job",
"posterEmail": "poster@linkedin.com",
"jobPostingOperationType": "CREATE",
"title": "Promoted Job Posting G1 TC1",
"description": "<b>Objective of the Position</b><br/> <ul> <li>To develop digital content plan, manage and monitor different content executions for social and online platforms to maximize the communication effectiveness and impact</li> <li>To manage, monitor and keep optimizing the performance of social platforms of MB and AMG</li> <li>To monitor and manage internet word of mouth to keep the health of brand and product image</li></ul>",
"listedAt": 1513756352000,
"location":"San Francisco, CA",
"industries": [
"urn:li:industry:55"
],
"listingType": "PREMIUM",
"partnerJobCampaignId": "abcd1234"
}
]
}
Note
- From PP4P General Availability (GA),
integrationContext - company or organization ID
orcompanyPageURL
is required to fill out. - Ensure that requests do not include duplicate updates to the same
externalJobPostingId
. The same contents under two differentexternalJobPostingId
will not be considered as a duplicate job. - It is mandatory to provide contract information in
integrationContext
orcontract
with the exception of the Recruitment Advertising Agency (RAA) partner. For RAA, please do not fill out thecontract
field, and the appropriate values will be looked up by the correct child application {access_token} associated with the right campaign. - If the
posterEmail
field is not provided or correct, the job will be posted on behalf of the default job poster email as it was configured in your contract. - For
budget.payForPerformanceTotalBudget.amount
, there will be 3-tier presets (low
,medium
&high
) you must decide before sending jobs with your LinkedIn Business Development (BD) counterpart. Please note that RAA jobs will load the budget from the associated campaign. - To update the JD/ATS individual job
budget
you must useRENEW
jobPostingOperationType
to send the request with the newamount
like a normalUPDATE
operation. The difference is that this will reset your job's duration to 30 days to the latest totalamount
. expireAt
will be fixed to 30 days from thelistedAt
for any P4P jobs. Only for RAA, as far as the associated job campaign exists, the job will auto-renew. To expire/stop P4P job(s), pleaseCLOSE
the job as immediately as possible.companyJobCode
is now required to provide to ensure the job quality especially if you are integrating with other LinkedIn products, such as Onsite Apply or Apply Connect, as the next enhancement. If you have the job's unique ID (also known as requisition ID) from the original source such as ATS, please provide that. Otherwise, you can duplicate anexternalJobPostingId
value into it.
Sample Request Body for Job Upgrade
Simple Job Posting (SJP) API supports an update of the created jobs, too. This is not a P4P-specific operation, and one can find general guidelines and expectations on the Update and Renew Jobs page. For P4P, if you have free/Basic jobs with LinkedIn, too, you can upgrade them to P4P jobs via this update operation. Please use Check the Job Operation Task Status API to check the asynchronous operation status as you do for regular API-posted jobs.
{
"elements":[
{
"integrationContext": "urn:li:company:{your_company_id}",
"contract": "urn:li:contract:{your_contract_id}",
"companyApplyUrl": "https://careers.yourcompany.com",
"externalJobPostingId": "UpgradeJobPostingG1TC1",
"posterEmail": "poster@linkedin.com",
"jobPostingOperationType": "UPDATE",
"title": "Upgraded Job Posting G1 TC1",
"description": "<b>Objective of the Position</b><br/> <ul> <li>To develop digital content plan, manage and monitor different content executions for social and online platforms to maximize the communication effectiveness and impact</li> <li>To manage, monitor and keep optimizing the performance of social platforms of MB and AMG</li> <li>To monitor and manage internet word of mouth to keep the health of brand and product image</li></ul>",
"listedAt": 1705648400000,
"location":"San Francisco, CA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "275.00"
}
},
"listingType": "PREMIUM"
}
]
}
Note
listingType
must bePREMIUM
andbudget
is mandatory to provide to upgrade a free job to P4P.- Once ugraded, the listing date of the job will be the time of the upgrade, and it will expire after 30 days from that date.
- Upgrade with an incorrect
budget.amount
, such as $1,000, will be rejected.
Sample Request Body for Job Downgrade
One can also downgrade a P4P job to the free/Basic job with the same update operation as you do to upgrade. Please use Check the Job Operation Task Status API to check the asynchronous operation status.
{
"elements":[
{
"integrationContext": "urn:li:company:{your_company_id}",
"contract": "urn:li:contract:{your_contract_id}",
"companyApplyUrl": "https://careers.yourcompany.com",
"externalJobPostingId": "DowngradeJobPostingG1TC1",
"posterEmail": "poster@linkedin.com",
"jobPostingOperationType": "UPDATE",
"title": "Downgraded Free Job Posting G1 TC1",
"description": "<b>Objective of the Position</b><br/> <ul> <li>To develop digital content plan, manage and monitor different content executions for social and online platforms to maximize the communication effectiveness and impact</li> <li>To manage, monitor and keep optimizing the performance of social platforms of MB and AMG</li> <li>To monitor and manage internet word of mouth to keep the health of brand and product image</li></ul>",
"listedAt": 1705648400000,
"location":"San Francisco, CA",
"industries": [
"urn:li:industry:55"
],
"listingType": "BASIC"
}
]
}
Note
listingType
must beBASIC
andbudget
should be removed to successfully downgrade a job.- Downgrading a job will not change created, listed and expiring dates of the job.
Sample Response Body
For Success
A successful request returns a 200 OK
response code, and you will find the simpleJobPostingTaskIDs
in the response body.
{
"elements": [
{
"id": "urn:li:simpleJobPostingTask:03ff7ca6-dedf-4d92-b856-10669f8fe5ef",
"status": 202
}
]
}
For Error
In case of an error, the request will return a 200 OK
response code and the error message is within the response body like an example below.
{
"elements": [
{
"error": {
"message": "ERROR :: /title :: field is required but not found and has no default value\n",
"status": 422
},
"status": 422
}
]
}
Note
- Please make sure to check and record the response for error status corresponding to an individual job you submit.
- The Task ids returned in the above responses are valid for 24 hours.
- Check the Job Operation Task Status to find the status of the job posting via above task ids.
- If you already have paid job contract with LinkedIn, please use the contract. If you post a P4P job that is already posted with the contract, your job will fail and considered as a duplicate. The same happens if you have already posted a P4P job, but you are trying to post the same free job.
API Error Details
In addition to the regular errors you can encounter with /simpleJobPostings
, you can have more errors and validations specific to P4P.
HTTP CODE | RESPONSE STATUS | ERROR MESSAGE | DESCRIPTION | RESOLUTION |
---|---|---|---|---|
400 | 400 | Please authenticate your LinkedIn contract with the LI job posting widget to promote your Job Post to a recommended budget. | Customer of the job already has a premium job posting (e.g.) contract with LinkedIn. | Please use the existing contract first before posting via P4P. |
400 | 400 | Invalid currencyCode was provided in the budget. Please check the contract for supported currencyCode. | No currency was setup for contract. | Please reach out to your Business Development contact to check the contract. |
400 | 400 | Invalid budget amount was provided in the parameter: {payForPerformanceTotalBudget={currencyCode=usd, amount=}} | No total budget was setup for contract. | Please reach out to your Business Development contact to check the contract. |
400 | 400 | Invalid budget amount was provided in the parameter: {payForPerformanceTotalBudget={currencyCode=usd, amount=1.000}} | Decimal places exceeded the limit of 2. | Please send a budget amount in the two decimal places of ".xx". |
400 | 400 | Invalid budget amount was provided in the parameter: {payForPerformanceTotalBudget={currencyCode=usd, amount=a}} | Amount was not a number. | Please send a numeric budget amount. |
400 | 400 | Invalid budget amount was provided in the parameter: {payForPerformanceTotalBudget={currencyCode=usd, amount=-1.00}} | Amount was not a positive number. | Please send a positive budget amount. |
400 | 400 | Invalid budget amount was provided in the parameter: {payForPerformanceTotalBudget={currencyCode=usd, amount=10001.00}} | Amount exceeded the budget limitation per job. | Please send a budget amount less than USD $10,000 per job. If your currencyCode is other than USD, then please do the conversion to match. |
400 | 400 | Job is not qualified to have a budget. | Your contract is not qualified for P4P, or the customer may already have a PJP (Premium) or other contract with LinkedIn. | Please make sure that the customer will need to post jobs to the existing contract first. To learn more about P4P, please reach out to your LinkedIn BD counterpart. |
400 | 400 | Invalid currencyCode was provided in the budget. Please check the contract for supported currencyCode. | currencyCode was empty or not recognizable. |
Please send a valid, ISO 4217 standard currencyCode . |
400 | 400 | Invalid currencyCode was provided in the budget. Please check the contract for supported currencyCode. | currencyCode was provided, but not matching with the currency in your P4P contract. |
Please reach out to your Business Development contact to check the contract. |
400 | 400 | The payloads for partner job {external-job-posting-id} creation must have field CompanyApplyUrl & sourceDomain. | Basic P4P job with no companyApplyUrl. | Please provide CompanyApplyUrl and sourceDomain . |
400 | 400 | The payloads for partner job {external-job-posting-id} creation must have field CompanyApplyUrl & sourceDomain. | Premium P4P job with no companyApplyUrl. | Please provide CompanyApplyUrl and sourceDomain . |
400 | 400 | The payloads for basic job {external-job-posting-id} creation must have field CompanyApplyUrl & sourceDomain. | Basic slot job with no companyApplyUrl. | Please provide companyApplyUrl . |
400 | 400 | The partner job campaign id is not found in the payload. | The partnerJobCampaignID is not provided in the payload. | Please provide a campaign id. |
400 | 400 | The partner job campaign does not exist. | The campaign provided in the payload does not exist. | Please provide a valid campaign id. |
400 | 400 | The partner job campaign is not active. | The campaign provided in the payload is not active. | Please provide a valid campaign id. |
400 | 400 | The customer contract does not exist for developer application {your Child application ID}. | The campaign provided in the payload is not active. | Please provide a valid campaign id. |
400 | 400 | The renew operation is not supported for this job. | The jobPostingOperationType is RENEW . |
Please use a valid operation type - CREATE /UPDATE /CLOSE . |
400 | 400 | The budget field should not be present in the payload for this job. | The budget field is included in the payload. |
Please remove the budget field. |
400 | 400 | The expireAt is not supported for this job. | The expireAt field is included in the payload. |
Please remove the expireAt field. |
400 | 400 | This job cannot be of type BASIC. | The listingType is BASIC . |
Please change the listingType to PREMIUM . |
402 | 402 | Payment Required returned for https://api.linkedin.com/v2/simpleJobPostings/. | Your contract is out of the budget . |
Please reach out to your Business Development contact to check the contract. |
406 | 406 | Operation type UPDATE is not allowed for a non-existing job of partner urn urn:li:partner:{your Parent application ID}, partner job code {your LinkedIn job code}. | The job you were you were trying to update did not exist. | Please re-CREATE your job after resolving the cause of the failure. You can know about the root causes by using the Job Operation Task Status API. |
422 | 422 | ERROR :: /budget/payForPerformanceTotalBudget/currencyCode :: field is required but not found and has no default value. | currencyCode was null and the field was not provided. |
Please send a valid, ISO 4217 standard currencyCode . |