# endorsePersonSkills

This method allows you to endorse every skill of a person whose name matches the patterns you specify, or all of their skills.

> LinkedIn lets you endorse skills only of your **1st-degree connections**. For anyone else, every selected skill gets `connectionNotFound` and nothing is endorsed.

> The method never removes an endorsement. A skill you have already endorsed is left as it is and reported as a success.

> To endorse one skill by its exact name, use [`endorsePersonSkill`](/sdks/endorse-person-skill).

```typescript
try {
  const workflow = await linkedapi.endorsePersonSkills.execute({
    personUrl: "https://www.linkedin.com/in/person1",
    skillNamePatterns: ["business", "project\\s*manage", "^(agile|scrum)$"]
  });

  const { data, errors } = await linkedapi.endorsePersonSkills.result(workflow.workflowId);

  // The list of possible execution errors is below
  if (errors && errors.length > 0) {
    console.warn('Workflow completed with execution errors:');
    errors.forEach(error => {
      console.warn(` - Type: ${error.type}, Message: ${error.message}`);
    });
  }

  // The structure of the 'data' object is below
  if (data) {
    data.forEach(endorsement => {
      if (endorsement.success) {
        console.log(`Endorsed: ${endorsement.skillName}`);
      } else if (endorsement.error) {
        console.warn(`Not endorsed: ${endorsement.skillName} - ${endorsement.error.type}`);
      }
    });
  }
} catch (e) {
  // A list of all critical errors can be found here:
  // https://linkedapi.io/sdks/handling-results-and-errors/#handling-critical-errors
  if (e instanceof LinkedApiError) {
    console.error(`Critical Error - Type: ${e.type}, Message: ${e.message}`);
  } else {
    console.error('An unexpected, non-API error occurred:', e);
  }
}
```

```python
from linkedapi import EndorsePersonSkillsParams, LinkedApiError

try:
    workflow = linkedapi.endorse_person_skills.execute(
        EndorsePersonSkillsParams(
            person_url="https://www.linkedin.com/in/person1",
            skill_name_patterns=["business", "project\\s*manage", "^(agile|scrum)$"],
        )
    )

    result = linkedapi.endorse_person_skills.result(workflow.workflow_id)
    data = result.data
    errors = result.errors

    # The list of possible execution errors is below
    if errors:
        print("Workflow completed with execution errors:")
        for error in errors:
            print(f" - Type: {error.type}, Message: {error.message}")

    # The structure of the 'data' object is below
    if data:
        for endorsement in data:
            if endorsement.success:
                print(f"Endorsed: {endorsement.skill_name}")
            elif endorsement.error:
                print(f"Not endorsed: {endorsement.skill_name} - {endorsement.error.type}")
except LinkedApiError as e:
    # A list of all critical errors can be found here:
    # https://linkedapi.io/sdks/handling-results-and-errors/#handling-critical-errors
    print(f"Critical Error - Type: {e.type}, Message: {e.message}")
except Exception as error:
    print("An unexpected, non-API error occurred:", error)
```

## Params

- `personUrl` – [public or hashed](/faq/what-are-hashed-url-and-public-url) LinkedIn URL of the person whose skills you want to endorse.
- `skillNamePatterns` (optional) – array of regular expressions that select skills by name. A skill is selected when **any** of the patterns matches its name. If omitted, every skill of the person is endorsed.
  - The syntax is [RE2](https://github.com/google/re2/wiki/Syntax), the dialect of Go `regexp` and Google Sheets `REGEXMATCH`. Ordinary patterns read like JavaScript or Python regular expressions, but lookaround (`(?=…)`, `(?!…)`, `(?<=…)`, `(?<!…)`) and backreferences (`\1`) are not supported.
  - Matching is case-insensitive and searches anywhere in the name: `manage` matches `Project Management`. To require the whole name to match, anchor the pattern with `^…$`: `^scrum$` matches `Scrum` but not `Scrum Master`.
  - In an ordinary string literal each backslash is written twice: `"project\\s*manage"` is the regular expression `project\s*manage`.
  - Skill names are shown as the profile owner entered them, in the owner's language, whatever your own LinkedIn language. Write patterns in the language of the profiles you target, or cover several languages in one pattern, such as `"proje[ck]t\\s*management"`.
  - The array holds 1 to 20 patterns, each 1 to 200 characters long. To endorse every skill, omit the parameter rather than passing an empty array. An empty array, an invalid pattern, or patterns over the matching-cost budget throw the critical error `invalidWorkflow` before the workflow starts. See [`st.doForSkills`](/docs/action-st-do-for-skills) for the full rules.

## Data

Array of the skills the patterns selected, in the order they appear on the person's profile. Skills that no pattern matched are not included; if none matched, the array is empty. Each item contains:

- `skillName` – name of the skill, as the profile owner entered it.
- `success` – whether the skill is endorsed. A skill you had already endorsed is reported as a success.
- `error` – object with the `type` and `message` of the reason the skill was not endorsed. Returned only when `success` is `false`. `type` is one of:
  - `connectionNotFound` – person is not your 1st-degree connection, so LinkedIn doesn't let you endorse their skills. Every selected skill gets this error.
  - `endorsementUnavailable` – LinkedIn offers no way to endorse this skill, for example because the person turned endorsements off.
  - `limitExceeded` – the account has reached its `stEndorsements` [limit](/sdks/admin-limits#limit-categories), so the skill was not endorsed. The limit is checked before each selected skill: once it is reached, skills get this error until earlier endorsements fall outside the limit period, so a later skill can still succeed. Check `success` on every item.
  - `unexpectedError` – the endorsement could not be completed or confirmed.

Selected skills are endorsed one at a time. A failed endorsement does not stop the others, and is reported only on its own item, not in `errors`.

## Errors

These errors mean the person's skills could not be read. The method then returns no data.

- `personNotFound` – provided URL is not an existing LinkedIn person.
- `personLikelyChangedPublicUrl` – provided URL no longer opens, but this person appeared in your account's [network events](/docs/monitoring-network) before, so they most likely changed their public URL. Retry with their [hashed URL](/faq/what-are-hashed-url-and-public-url).
- `selfProfileNotAllowed` – action cannot be performed on your own profile.
- `limitExceeded` – the account has reached its `stPersonProfileViews` [limit](/sdks/admin-limits#limit-categories), so the profile was not opened.

Opening the profile counts toward `stPersonProfileViews`, and each successful endorsement counts toward `stEndorsements`.

See [Endorsing skills](/docs/endorsing-skills) for the workflow this method runs and its completion.
