# Resolve

`POST https://api.serpkite.com/v1/resolve` · Credits: Free

Destinations of links a batch job or monitor run returned with link_resolved: false, which Google held back past the request. Free.

Google links every result through a `google.com/goto` redirect, and for a few results per page it holds the destination back for seconds, sometimes longer than a request lasts. SerpKite keeps such a result in its position with `link_resolved: false`. Its `link` is then still Google's redirect and its `domain` is the host Google displayed. `meta.unresolved_links` counts them.

For batch jobs and monitor runs SerpKite goes on following those redirects after Google's delay, for up to 2 minutes, and they wait for them, so their results rarely carry any. Send such links here to get their destinations; a `pending` link comes with `retry_after` seconds to wait. Links held back from a live request are not followed after the response and come back `failed`: repeat the search, or run it as a [batch job](https://serpkite.com/docs/endpoints/batches), to get them.

## Request body

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `links` **required** | string[] |  | 1 to 100 `link` values of results with `link_resolved: false`, as returned (`https://www.google.com/goto?url=…`). |

## Example request

cURL:

```bash
curl https://api.serpkite.com/v1/resolve \
  -H "Authorization: Bearer $SERPKITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"links":["https://www.google.com/goto?url=CAESgwEB6zsw"]}'
```

TypeScript:

```ts
import { SerpKite } from "serpkite";

const sk = new SerpKite(); // reads SERPKITE_API_KEY
const res = await sk.search({ links: ["https://www.google.com/goto?url=CAESgwEB6zsw"] });
console.log(res.results[0].title, res.meta.credits_used);
```

Python:

```python
from serpkite import SerpKite

sk = SerpKite()  # reads SERPKITE_API_KEY
res = sk.search(links=["https://www.google.com/goto?url=CAESgwEB6zsw"])
print(res.results[0].title, res.meta.credits_used)
```

## Response fields

| Field | Type | Description |
| --- | --- | --- |
| `results[]` | array | One per link, in order: `link`, `status` (`resolved`, `pending`, `failed`: Google never released it, `unknown`: not a link SerpKite returned in the last 24 hours), and `destination` and `domain` when resolved. |
| `retry_after` | integer | Seconds to wait before asking again for the `pending` links (also sent as `Retry-After`). Absent when none is pending. |
| `meta` | object | `request_id` and `credits_used` (always 0). |

## Example response

```json
{
  "results": [
    {
      "link": "https://www.google.com/goto?url=CAESgwEB6zsw",
      "status": "resolved",
      "destination": "https://www.example.com/espresso-guide",
      "domain": "example.com"
    }
  ],
  "meta": {
    "request_id": "01JC8S9V5Q4ZB3H6M2N7P0R1T4",
    "credits_used": 0
  }
}
```

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_request` | A parameter is missing or invalid. |
| 401 | `unauthorized` | The API key is missing, invalid or revoked. |
| 402 | `insufficient_credits` | Your balance is too low. Buy a pack or wait for the monthly free grant. |
| 429 | `rate_limited` | Too many requests per second for your plan. Retry after the Retry-After header. |
| 503 | `upstream_error` | Google could not be fetched or parsed. Not billed; retry after Retry-After. |

All errors: https://serpkite.com/docs/errors

## Notes

- Not billed; counts toward the key's rate limit.
- It never follows arbitrary redirects: only links SerpKite returned unresolved are known.

## Related

- [Response meta (unresolved_links)](https://serpkite.com/docs/response-headers#body-meta)
- [Rank tracking guide](https://serpkite.com/docs/guides/rank-tracking)