APRESLY API V1

API v1 reference

Endpoints, authentication, parameters, responses and limits for the Apresly public API. Import the OpenAPI specification.

Verified against the production API: October 9, 2026

On this page

Base URL and authentication

Base URL: https://app.apresly.com/api/public/v1. All three operations require Authorization: Bearer <YOUR_API_KEY>. Create your key in API settings. Use it only from your server or a private automation connection.

Download OpenAPI 3.1 for Postman or a client generator. This website’s copy uses the absolute production URL. The live API specification uses a relative server path and does not require a key.

List campaigns

GET /campaigns

Returns your account’s campaigns in ascending ID order. Without a filter, both drafts and published campaigns are included.

Query parameter Value Purpose
limit 1-100, default 50 Campaigns per page
afterId Positive integer nextAfterId from the previous response
isDraft true or false false: published, true: drafts
curl --fail-with-body "https://app.apresly.com/api/public/v1/campaigns?isDraft=false&limit=50" \
  -H "Authorization: Bearer $APRESLY_API_KEY"
{
  "items": [
    {
      "id": 42,
      "name": "Post-purchase upsell",
      "type": {
        "id": 1,
        "name": "Campaign type"
      },
      "isDraft": false
    }
  ],
  "nextAfterId": null
}

A 200 response contains items and nextAfterId. Each campaign has id, name, type (id and name) and isDraft. Null nextAfterId means the last page. Otherwise request, for example, /campaigns?isDraft=false&limit=50&afterId=42, using the returned cursor.

Register a lead

POST /campaigns/{campaignId}/leads

campaignId is a positive campaign ID belonging to the key’s account. The campaign must be published. Send Content-Type: application/json and only the following fields.

JSON field Required Value
email Yes Valid email, at most 254 characters, no leading or trailing whitespace
language No en or pl, default en; language of the countdown image
curl --fail-with-body -X POST "https://app.apresly.com/api/public/v1/campaigns/42/leads" \
  -H "Authorization: Bearer $APRESLY_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"email":"[email protected]","language":"en"}'

201 means a new logical lead; 200 means an existing lead. A draft returns 409 / CAMPAIGN_NOT_PUBLISHED without registration. Keep email spelling, case and + aliases consistent across integrations, as they identify the lead. Do not send deadline, clientId or an IP address.

Look up an existing offer

POST /campaigns/{campaignId}/leads/lookup

Uses the same JSON and headers as registration. Returns 200, without created. It does not register the lead, activate or renew the countdown. POST keeps the email out of the request URL. Authentication, rate limits and request history still apply.

curl --fail-with-body -X POST "https://app.apresly.com/api/public/v1/campaigns/42/leads/lookup" \
  -H "Authorization: Bearer $APRESLY_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"email":"[email protected]","language":"en"}'

A missing lead returns 404 / LEAD_NOT_FOUND. An expired deadline can be returned. A historical lead in a draft returns CAMPAIGN_NOT_PUBLISHED in warnings, with no links or timer.

Response fields

This illustrative registration response comes from a campaign without offer pages or an email timer. Dates and IDs are examples.

{
  "campaignId": 42,
  "email": "[email protected]",
  "registeredAt": "2026-09-12T12:00:00.000Z",
  "deadline": "2026-09-14T12:00:00.000Z",
  "timeZone": "Europe/Warsaw",
  "offerLinks": [],
  "mailTimerUrl": null,
  "warnings": [
    "NO_OFFER_PAGES",
    "NO_MAIL_TIMER"
  ],
  "created": true
}
Field Meaning
campaignId Campaign ID.
email Email sent in the request.
registeredAt First retained registration or activation, ISO 8601 UTC. Not the response time.
deadline Actual campaign deadline in UTC, or null when not determined.
timeZone Campaign time zone, e.g. Europe/Warsaw.
offerLinks Array of eligible pages sorted by pageId. May be empty.
offerLinks[].pageId Page ID; use it to select the intended offer.
offerLinks[].pageUrl Configured page URL.
offerLinks[].url Personalized CTA link. Use this URL in your button.
mailTimerUrl Email countdown image URL or null.
warnings Warnings about unavailable resources. See the troubleshooting guide.
created Registration only. true when no identifiable lead existed before the request.

The API follows existing deadline, reset and cycle settings. Repeated registration does not extend the deadline when reset is disabled. created describes lead identity, not a new cycle or exactly-once email delivery.

The API does not send emails. It does not replace the widget: existing pages and the installed widget enforce HIDE, ZERO or REDIRECT on expiration. Constructing a URL does not activate an offer; opening a CTA or timer image follows standard campaign behavior.

Personalized links can be forwarded. They contain recipient identity and are not secret, single-use access tokens. Changes to campaign pages or settings may change later responses. Revoking a key does not invalidate previously issued links.

Limits and retries

  • Default: 120 authorized requests per UTC minute per account, shared across all keys. This is a service-side configurable limit.
  • JSON body maximum: 16 KiB. Unknown fields and query parameters are rejected.
  • Lists: 1-100 items, default 50.
  • On 429, wait for the number of seconds in Retry-After.
  • Retry timeouts and 503 with increasing backoff and a bounded number of attempts.
  • A lost response does not mean the registration was rolled back. Deduplicate events and email delivery in your system, rather than relying only on created.

Errors and diagnostics

Errors contain status, code, message and requestId. API responses also include X-Request-Id and Cache-Control: no-store headers. Keep keys, emails and personalized links out of logs.

{
  "status": "error",
  "code": "UNAUTHORIZED",
  "message": "Invalid API key",
  "requestId": "00000000-0000-4000-8000-000000000001"
}
HTTP Code
400 INVALID_JSON, INVALID_CURSOR
401 UNAUTHORIZED
403 ACCOUNT_SUSPENDED
404 CAMPAIGN_NOT_FOUND, LEAD_NOT_FOUND, NOT_FOUND
409 CAMPAIGN_NOT_PUBLISHED
413 PAYLOAD_TOO_LARGE
415 UNSUPPORTED_MEDIA_TYPE
422 VALIDATION_ERROR
429 RATE_LIMITED
500 INTERNAL_ERROR
503 SERVICE_UNAVAILABLE

Find fixes for errors and warnings. Request history in the panel covers the last 7 days by default, without payloads, emails or secrets. Audit-storage outages may leave gaps.

Next guideConnect with Make

NEED A HAND?

Let’s work through your integration.

Tell us what you’re connecting. For a failed request, include the requestId and error code, without your API key or customer data.

Contact support