e-satisfaction

API reference

e-sat.ly has a small HTTP API for creating short links from your own systems. There are two endpoints for creating a link and one for listing them, and everything authenticates with a project's API key.

Base address: https://e-sat.ly

Which endpoint should I use?

Use /api/v1/links for anything new — it's JSON, it returns the full link, and it can list links back to you.

/create is the original endpoint and it isn't going anywhere: it's what the suite's own shortener client calls, and it's kept compatible on purpose. Use it if you're already using it, or if you need to post form-encoded data.

Authentication

Every request carries your project's API key in the Authorization header:

Authorization: Bearer YOUR_PROJECT_KEY

This works on every endpoint. The key identifies the project and its organization, so you never send an organization id or project id — the link simply lands in the project the key belongs to.

A missing or unrecognized key gets a 401. Copy your key from Configuration → Projects, and see Projects & API keys for re-issuing.

POST https://e-sat.ly/api/v1/links
Content-Type: application/json
ParameterTypeRequiredDescription
urlstringYesThe destination. Must be an absolute http:// or https:// URL.
codestringNoYour own short code — 1–10 letters and numbers. Omit it and one is generated for you.
expiresAtstringNoWhen the link should stop redirecting, as a date. Omit it and the link never expires.
pinnedbooleanNotrue pins the link so it's never cleaned up. Defaults to false.

Example

curl -X POST https://e-sat.ly/api/v1/links \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/survey?id=12345"}'
{
  "code": "4kQm2",
  "url": "https://example.com/survey?id=12345",
  "shortUrl": "https://e-sat.ly/4kQm2",
  "createdTime": "2026-07-17T09:31:04.000Z",
  "expiresAt": "2123-09-20T17:14:30.000Z",
  "pinned": false
}

shortUrl is the link to send. Returns 201.

That expiry date in the year 2123

A link that never expires reports a placeholder date far in the future rather than an empty value. If expiresAt is in 2123, read it as "never expires". Don't read it as "kept until 2123" — how long a link is kept is data retention, which is a different thing entirely.

With an expiry

curl -X POST https://e-sat.ly/api/v1/links \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://example.com/promo",
        "expiresAt": "2026-12-31T23:59:59Z"
      }'
curl -X POST https://e-sat.ly/api/v1/links \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://example.com/poster-campaign",
        "pinned": true
      }'

pinned and expiresAt can't be combined

Sending both is rejected with a 400 rather than resolved by guessing. A pinned link never expires, so the two instructions contradict each other — and picking a winner silently would either kill a link meant to live forever or keep one meant to die. Send one or the other.

A custom code

curl -X POST https://e-sat.ly/api/v1/links \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://example.com/spring",
        "code": "spring26"
      }'

If the code is already taken you get a 409. Codes are case-sensitive.

Creating the same URL twice

Creating a link for a URL your project has already shortened returns the existing link — the same code — instead of minting a second one. Retries and re-runs are safe.

Two details worth knowing:

  • The check is per project. A different project shortening the same URL gets its own separate link.
  • Sending pinned: true for a URL that already has a link pins the existing link rather than returning it unchanged — you asked for a pinned link, so you get one. A normal create (pinned omitted or false) never unpins an existing link.
GET https://e-sat.ly/api/v1/links

Returns up to 100 links from the key's project, newest first, each with its click count.

curl https://e-sat.ly/api/v1/links \
  -H "Authorization: Bearer YOUR_PROJECT_KEY"
{
  "data": [
    {
      "code": "4kQm2",
      "url": "https://example.com/survey?id=12345",
      "shortUrl": "https://e-sat.ly/4kQm2",
      "clicks": 3,
      "createdTime": "2026-07-17T09:31:04.000Z",
      "expiresAt": "2123-09-20T17:14:30.000Z",
      "pinned": false
    }
  ]
}

This endpoint is a convenience for checking your own recent links, not a reporting API — there's no paging, filtering or date range. For real analysis use the console's Clicks screens.

The /create endpoint

POST https://e-sat.ly/create

The original endpoint, kept compatible for existing integrations. Same authentication; different parameter names and a different response shape.

ParameterTypeRequiredDescription
urlstringYesThe destination. Absolute http:// or https://.
expiration_datestringNoWhen the link stops redirecting. Omit and it never expires.
pinnedboolean-ishNoPins the link. Accepts true, 1, on or yes.

Unlike /api/v1/links, this endpoint accepts JSON, form-encoded or multipart bodies interchangeably — which is why pinned takes string forms like "1" here, since a form field can't carry a real boolean.

curl -X POST https://e-sat.ly/create \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/survey?id=12345"}'
{
  "status": true,
  "long_url": "https://example.com/survey?id=12345",
  "short_url": "https://e-sat.ly/4kQm2",
  "pinned": false
}

Form-encoded, which is equally valid:

curl -X POST https://e-sat.ly/create \
  -H "Authorization: Bearer YOUR_PROJECT_KEY" \
  -d "url=https://example.com/survey?id=12345" \
  -d "pinned=1"

Like /api/v1/links, it deduplicates per project and it rejects pinned together with expiration_date.

Errors

Both create endpoints use standard status codes. /api/v1/links returns {"error": "…"}; /create returns {"status": false, "error": "…"}.

CodeMeaningCommon causes
400The request was wrongurl missing or not an absolute http(s) URL; an unparseable date; a code that isn't 1–10 letters and numbers; pinned sent with an expiry; malformed JSON
401Authentication failedKey missing, mistyped, or re-issued since your system last got it
409ConflictThe code you asked for is already taken

A 401 that appears suddenly on an integration that was working almost always means the project key was re-issued and the new value hasn't reached your system yet.

Practical notes

  • Store the key as a secret. It creates links in your project and lists what's there. Keep it in your environment configuration or secret store, never in front-end code or a repository.
  • Send the shortUrl you get back. Don't build the link yourself by gluing the domain to the code.
  • A created link is not a kept link. Every link you create through the API is transactional unless you pin it, which means it's cleaned up once it ages past your project's retention window. If your integration creates links that need to live forever, pass pinned: true.
  • You don't need this for survey sends. The suite already shortens SMS and Viber links for you — see URL shorteners. The API is for links your own systems create.