Pay For Performance (P4P) Job Posting
LinkedIn's Pay For Performance (P4P) Job Posting enables the posting of P4P jobs to LinkedIn. P4P Job Posting is an extension of LinkedIn's Job Posting, more specifically Promoted Jobs. We encourage you to read about the non-P4P Job Posting to aim for even better solution overviews. If you want to head start with request samples, you can request access to the Postman collection above as a viewer to fork and create your branch.
What To Expect
Important
Please read below thoroughly to understand the right next steps.
Implementation requirements vary depending on your offering and objectives. Once you start development, please don't forget to read P4P Job Posting Schema for any fields you will send to request payloads for important tips:
- For fundamentals, to view your P4P job and budget metrics, 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 (LTS) 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. - Additionally to 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 P4P Job Posting API below.
To help understand here is a brief diagram of what the Parent-Child Developer Application relationship is like and how to activate your client per different LTS product: Having child applications is important, especially for two reasons: 1) it enables better controlling and analyzing of data per end client and 2) it makes future onboarding to other LTS products, such as Apply Connect/Onsite Apply, smoother as they are following the same ecosystem. LinkedIn requires a Company ID or Page URL of the job in a request payload, so we strongly recommend having a 1:1 mapping between one child app and one customer of yours that can be represented by one Company ID or Page URL. If the client has multiple entities that have different accounts/contracts with you, it is okay to have one child app to resent one branch of the company for your convenience. However, having a child app to represent different companies may cause additional migration efforts.
Once development is completed and ready for certification, please contact your Partner Solutions Engineer and Business Development contacts to setup a meeting.
P4P Job Posting API
To post a job as P4P, you need to provide the listingType
field value as PREMIUM
with the right parent (or partner-level) contract. Please don't forget to read the bullet points in the "Note" boxes as they contain valuable tips. Only selective partners have 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. Please visit Job Posting Overview to learn more about the Simple Job Posting (SJP) API.
LinkedIn Job Postings have three states in the lifecycle: 1) Before Creation (you are preparing a job), 2) Listed (the job is live after asynchronous processing), and 3) Closed (to be deleted). To manage each state, there are four operation types you can control with jobPostingOperationType
: CREATE, UPDATE, RENEW, and CLOSE. UPDATE
and RENEW
can be only processed if the job is not closed. Please see below for each operation details.
You will notice that P4P sample requests do not have listedAt
and expireAt
specified. P4P jobs will be listed from the moment the job has been successfully processed, so listedAt
will not be honored. P4P jobs will be automatically set to a duration of 30 days, so expireAt
will be ignored, too. To pause or stop the P4P job earlier than 30 days, please use jobPostingOperationType: CLOSE
to close it early. Once the job is closed, you cannot re-open it, and you must freshly create with a new budget and 30-day duration to re-list the same job contents. To extend your job campaign, consider using jobPostingOperationType: RENEW
.
All LinkedIn job postings go through asynchronous processing to validate before successfully listing them. To track status, you are now required to develop a status checking/logging mechanism for both Check the Job Operation Task Status and Check Job Posting Statuses, so you and your clients are quickly up-to-date about any glitches during processing. This reduces the overhead of waiting for a support ticket response and allows the job requester to correct the flagged values immediately to repost.
You can also use Check Job Posting Statuses API to check if your or your customer's job has been caught in our Job Trust review. If in the case a reviewer catches any job content that is not compliant with LinkedIn Jobs Terms & Conditions, your default job administrator will receive a notification in email for further action, and you will see the job is in review from this API response. As the next step, you can appeal the review to unlock your job listing again, but if the review was valid, then you will need to close the job in review to create a new job after correcting the violations.
Setup HTTP Request
Note
- All requests below require access tokens obtained via the OAuth2.0 Client Credentials flow. We strongly recommend to use same access token for all concurrent and consecutive calls. An access token has a lifespan of 30 mins. Only on expiry of the existing token should a new token should be generated.
- You should generate the {access_token} from the Child Developer Application (created via Provisioning API) that represents each Client account of yours.
curl --location --request POST 'https://api.linkedin.com/v2/simpleJobPostings' \
--header 'Authorization: Bearer {access_token}' \
--header 'x-restli-method: batch_create'
CREATE New Job
Note
integrationContext
(company or organization ID) orcompanyPageURL
is required.- For
budget
, there will be 3-tier presets (low, medium & high). Please discuss this with your LinkedIn Business Development (BD) counterpart. 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.companyApplyUrl
does not support an email address or "mailto:". Please consider generating a Short URL from the email address to send.
Sample Request Body for Job Creation
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_job-id",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "CREATE",
"title": "Partner P4P Test Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "299.00"
}
},
"listingType": "PREMIUM"
}
]
}
UPDATE Existing Job
Any live, not closed, jobs can be updated with new field values with "UPDATE" jobPostingOperationType
. For P4P jobs, listedAt
, expireAt
, and budget
are NOT modifiable by this operation. To change a P4P job duration and budget, please see below RENEW Existing Job. location
, title
, and description
are the most popular examples to update.
Note
- Even if you provide values in
listedAt
,expireAt
, andbudget
to update, they will be ignored.
Sample Request Body for Job Update
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_job-id",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "UPDATE",
"title": "Partner P4P Test Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"listingType": "PREMIUM"
}
]
}
RENEW Existing Job
For P4P jobs, you can renew the existing, live job with a new budget amount. This resets the job to a new 30-day duration and given amount. For example, if the job had a remaining budget of $15 3 days before expiration and you posted a RENEW request with a new budget of $399, then the job will now have a new 30-day duration with a new total budget of $399. In this case, the total budget this job spent at the end of its lifecycle will be the amount to be invoiced.
Note
- You cannot renew for more or less than another 30-day duration. You must close the renewed job if you want to campaign it in less than 30 days.
- If job is already closed, you cannot renew it. Pleas create a new job in this case.
Sample Request Body for Job Renew
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_job-id",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "RENEW",
"title": "Partner P4P Test Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "399.00"
}
},
"listingType": "PREMIUM"
}
]
}
CLOSE Existing Job
While P4P jobs will be automatically closed/expired after 30 days from the time listed, you can close the job early to stop. Once the job is closed, it will stop spending a budget and be unlisted from the job board. Please note that we keep logs for up to 7 days for any closed/deleted jobs.
Note
- You cannnot pause a P4P job. You will need to stop and re-list/re-create the same job to resume.
- If the job is closed, it will be deleted from our system, so you can create a new job with the previously used
externalJobPostingId
.
Sample Request Body for Job Close
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_job-id",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "CLOSE",
"title": "Partner P4P Test Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "299.00"
}
},
"listingType": "PREMIUM"
}
]
}
Upgrade Job
As you know, 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, you can upgrade them to P4P jobs via this update operation, too. Please use Check the Job Operation Task Status API to check the asynchronous operation status as you do for regular API-posted jobs.
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 Upgrade
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_non-p4p-job-id_to_upgrade",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "UPDATE",
"title": "Partner P4P Test Upgraded Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"budget": {
"payForPerformanceTotalBudget": {
"currencyCode": "USD",
"amount": "299.00"
}
},
"listingType": "PREMIUM"
}
]
}
Downgrade Job
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.
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 Request Body for Job Downgrade
{
"elements":[
{
"integrationContext": "urn:li:company:{customer-company_id}",
"companyPageUrl": "https://www.linkedin.com/company/customer_company-page_url",
"contract": "urn:li:contract:{your-contract_id}",
"companyApplyUrl": "https://careers.customer-company.com",
"externalJobPostingId": "your-unique_non-p4p-job-id_to_downgrade",
"companyJobCode": "ATS-source-requisition_id_or_externalJobPostingId",
"jobPostingOperationType": "UPDATE",
"title": "Downgraded Free Job",
"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>",
"location":"San Francisco, CA, USA",
"industries": [
"urn:li:industry:55"
],
"listingType": "BASIC"
}
]
}
Sample Response Body for Job Posting API
Note
- The Task IDs returned in the below responses are valid for 24 hours.
- Please make sure to check and record the response for error status corresponding to an individual job you submit. You can use Check the Job Operation Task Status to find the status of the job posting with the Task ID below.
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
}
]
}
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 | Job postings for the company {the company name in error} are restricted due to company policies. Please contact your administrator for more details. | Please check with your LinkedIn Business Development counterpart if you think this restriction is invalid. The most common reason can be that the company already has another LinkedIn product which may be conflicting with this job posting. | |
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 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 . |