Skip to main content
POST https://api.linkskipper.app/v1/resolve · Requires the resolve scope.
Submit a supported shortener URL. If the link has already been resolved, the destination comes back immediately with HTTP 200. Otherwise the link is queued for background resolution and you get HTTP 202 with a job to poll (or a webhook delivery).

Request

Headers

string
required
Bearer sk_live_…. See Authentication.
string
required
application/json.
string
Optional. De-duplicates retries. Equivalent to the idempotency_key body field — if both are present, the body field wins. Max 128 characters. See Idempotency.

Body

string
required
The shortener URL to resolve. Max 2048 characters. Must be a link from a supported provider; anything else returns unsupported_link (422).
string
Optional de-duplication token, max 128 characters. A repeated request with the same key returns the existing job’s current state instead of starting a new resolve. Takes precedence over the Idempotency-Key header.
string
Optional public HTTPS callback. When the job reaches a terminal status, Link Skipper sends a signed POST to this URL. Max 2048 characters. Loopback, private, link-local, and .localhost / .internal hosts are rejected at validation time. See Webhooks.
Request body

Response

The endpoint returns one of two shapes depending on whether the link was already cached.

200 — resolved (cached)

Returned when the link was already in cache. job_id is null because no job was created, cached is true, and credits_charged is 0 (cached reads are free).
string | null
null for a cached, synchronous resolve.
string
"done".
string
The URL you submitted (echoed back).
string
The final destination the shortener points to.
string
The provider that owns the link (e.g. ouo). See Providers.
string
"standard" or "premium".
number
0 for a cached resolve.
boolean
true for a cached resolve.
number | null
Your remaining credit balance after the call.
200 OK

202 — queued

Returned when the link must be resolved in the background. Poll the poll_url (the jobs endpoint) until the job is terminal, or supply a webhook_url to be notified.
string
The UUID of the queued job. Use it with GET /v1/jobs/{job_id}.
string
"queued".
number
Approximate position in the resolve queue at submission time.
string
Relative path to poll for the result, e.g. /v1/jobs/{job_id}.
202 Accepted

Examples

The SDK resolve() methods submit the URL and (optionally) an idempotency key. To pass a webhook_url, send a raw HTTP request, or use the dashboard. To resolve and wait for the result in one call, use resolveAndWait.

Synchronous vs queued

Cached → 200

The link was resolved before. The destination comes back in the same response, cached: true, and you are not charged.

New → 202

The link is queued. You get a job_id and poll_url. Credits are only charged when the job succeeds.
You don’t choose between the two — the API returns whichever applies. Always branch on the HTTP status (or the status field) so your code handles both.

Idempotency

A POST /v1/resolve is not naturally idempotent: a naive retry after a dropped connection could queue a second job and charge twice. Send an idempotency key to make retries safe. When you supply idempotency_key (body) or Idempotency-Key (header):
  • The first request with that key starts the resolve and remembers the resulting job.
  • Any repeat with the same key returns that job’s current state as-is — it does not start a new resolve and does not charge again. While the job is still running you get the 202 queued shape back; once it finishes you get the resolved 200 shape.
  • Idempotency keys are scoped per API key. Use a stable, unique value per logical operation (an order id, a content id, a UUID you generate).
Safe retry
A replay of a key whose job ended in failure surfaces the same terminal error: resolve_failed for a failed job, unsupported_link for an invalid one.

Errors

See Errors for the full envelope and handling guidance, and Rate limits for Retry-After behavior.