REST API Reference
These endpoints are the same ones the OpenLynk mobile SDKs call. You can also call them directly from your backend (admin panels, invite services, scripts) using your app's SDK API key.
:::tip Common use case
Invite users from an admin panel: create an Openlynk link with POST /api/links/create-sdk, put link.url in the email, and let Openlynk handle open-app vs download. See Create invite links from your server.
:::
Base URL: https://openlynk.io
Authentication
Most endpoints require a per-app API key via either header:
x-openlynk-sdk-key: ol_your_api_key_here
or:
Authorization: Bearer ol_your_api_key_here
| Detail | Value |
|---|---|
| Key format | ol_ + 32 hex characters |
| Scope | Single app |
| Where to create | Dashboard → your app → SDK API Key |
appId | Derived from the key for authenticated routes — do not rely on body appId for auth |
Keys are stored as SHA-256 hashes. Openlynk never stores plaintext. If you lose a key, rotate it in the dashboard.
:::warning Server-side use When calling these endpoints from a backend, keep the API key in a secrets manager or environment variable. Never commit it to source control. The same key may also be embedded in your mobile app — treat it as sensitive and rotate it if leaked. Dedicated server-only keys are planned as a follow-up. :::
Quick reference
| Method | Endpoint | Auth | Rate limit |
|---|---|---|---|
POST | /api/links/create-sdk | API key | 10 req/min/IP |
GET | /api/links/get-by-slug | None | 30 req/min/IP |
POST | /api/deferred-deep-linking/restore | API key | 20 req/min/IP |
POST | /api/deferred-deep-linking/install-heartbeat | API key | 10 req/min/IP |
POST | /api/deferred-deep-linking/store | API key | 20 req/min/IP |
POST | /api/push/register | API key | 20 req/min/IP |
POST | /api/push/opened | API key | 30 req/min/IP |
Link creation
POST /api/links/create-sdk
Creates a dynamic deep link. This is the primary endpoint for in-app sharing and server-side invite links.
Headers:
Content-Type: application/json
Authorization: Bearer ol_your_api_key_here
Request body:
{
"destination": "/invite/abc123",
"metadata": {
"invite_id": "abc123",
"utm_source": "email",
"utm_medium": "invite"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
destination | string | Yes | Relative path starting with / (query string allowed). Must not start with //. |
metadata | object | No | Custom key-value data attached to the link (UTM params, invite IDs, etc.) |
The server generates the link slug automatically ({timestamp}-{random}).
curl example:
curl -X POST https://openlynk.io/api/links/create-sdk \
-H "Authorization: Bearer ol_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"destination": "/invite/abc123",
"metadata": {
"invite_id": "abc123",
"utm_source": "email"
}
}'
Response (200):
{
"success": true,
"link": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "1734567890-a1b2c3d4",
"url": "https://myapp.openlynk.to/1734567890-a1b2c3d4",
"destination": "/invite/abc123",
"metadata": {
"invite_id": "abc123",
"utm_source": "email",
"destination_path": "/invite/abc123",
"destination_full": "/invite/abc123",
"created_via": "sdk"
}
}
}
Use link.url in emails, SMS, or any share channel. When the recipient taps it, Openlynk opens the app if installed, or routes them to install and restores the destination via deferred deep linking.
Errors:
| Status | When |
|---|---|
400 | Missing or invalid destination |
401 | Missing or invalid API key |
403 | Generated-link plan limit reached (GENERATED_LINKS_LIMIT_REACHED) |
404 | App not found |
429 | Rate limited |
Link resolution
GET /api/links/get-by-slug
Resolves a link slug to destination and metadata. Used by SDKs when handling an incoming deep link.
Auth: Not required. Rate-limited by IP.
Query parameters:
| Param | Required | Description |
|---|---|---|
slug | Yes | Link slug |
appId | Conditional | App UUID. Required unless hostname can resolve the app |
hostname | Conditional | Host used to resolve the app (platform subdomain or custom domain) when appId is omitted |
Example:
curl "https://openlynk.io/api/links/get-by-slug?slug=1734567890-a1b2c3d4&appId=YOUR_APP_ID"
Response (200):
{
"success": true,
"link": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "1734567890-a1b2c3d4",
"destination_web_url": "/invite/abc123",
"destination_path": "/invite/abc123",
"destination": "/invite/abc123?invite_id=abc123",
"parameters": {
"invite_id": "abc123",
"utm_source": "email"
},
"metadata": { }
}
}
Deferred deep linking
POST /api/deferred-deep-linking/restore
Restores pending links after install (or on SDK init). Prefer calling this from the mobile SDK; documented here for parity and advanced integrations.
Request body:
{
"deviceFingerprint": "fp_abc123def456"
}
| Field | Type | Required | Description |
|---|---|---|---|
userEmail | string | One of email or fingerprint | Email to match pending links |
deviceFingerprint | string | One of email or fingerprint | Client device fingerprint |
appId is taken from the API key.
Response (200):
{
"success": true,
"restoredLinks": [
{
"pendingLinkId": "pending-link-uuid",
"originalUrl": "https://myapp.openlynk.to/abc123",
"destination_url": "/product/123?ref=share",
"destination": "/product/123?ref=share",
"destination_path": "/product/123",
"metadata": { "campaign": "summer-sale" },
"parameters": { "campaign": "summer-sale" },
"linkId": "550e8400-e29b-41d4-a716-446655440000"
}
],
"count": 1,
"message": "Restored 1 pending links"
}
Matching priority: email → device fingerprint → IP / user-agent fallbacks on the server.
POST /api/deferred-deep-linking/install-heartbeat
Reports an install or heartbeat. The SDK throttles this to about once per 24 hours per device.
Request body:
{
"deviceFingerprint": "fp_abc123def456"
}
| Field | Type | Required | Description |
|---|---|---|---|
deviceFingerprint | string | Yes | Device fingerprint |
Response (200):
{
"success": true,
"isFirstLaunch": true
}
POST /api/deferred-deep-linking/store
Stores a pending link for deferred deep linking. Openlynk's link resolver usually does this automatically when a user clicks a link without the app installed. You rarely need to call this yourself.
Request body:
{
"linkId": "550e8400-e29b-41d4-a716-446655440000",
"originalUrl": "https://myapp.openlynk.to/abc123"
}
| Field | Type | Required | Description |
|---|---|---|---|
linkId | string | Yes | ID of the clicked link |
originalUrl | string | No | Full URL the user clicked |
userEmail | string | No | User email if known |
Response (200):
{
"success": true,
"pendingLinkId": "pending-link-uuid"
}
Push notifications
POST /api/push/register
Registers a device push token (FCM / APNs). Called by the mobile SDK.
Request body:
{
"deviceToken": "fcm-or-apns-device-token",
"platform": "android",
}
| Field | Type | Required | Description |
|---|---|---|---|
deviceToken | string | Yes | FCM or APNs device token |
platform | string | Yes | "ios" or "android" |
userEmail | string | No | Associate the token with a user |
The field name is deviceToken (not token).
Response (200):
{
"success": true
}
POST /api/push/opened
Logs that a user opened a push notification (analytics).
Request body:
{
"notificationId": "notification-uuid",
"deviceToken": "fcm-or-apns-device-token"
}
| Field | Type | Required | Description |
|---|---|---|---|
notificationId | string | Yes | ID of the push notification |
deviceToken | string | No | Device token that opened it |
Response (200):
{
"success": true
}
POST /api/push/send
Sends a push notification to registered devices.
This endpoint requires dashboard session authentication, not an SDK API key. It is not for client or SDK-key backends.
Error responses
Authenticated endpoints return JSON errors:
{
"error": "Description of the error"
}
| Status | Meaning |
|---|---|
400 | Invalid request body or query params |
401 | Missing or invalid API key |
403 | Plan limit reached (e.g. generated links) |
404 | Resource not found |
429 | Rate limited |
500 | Server error |
On link creation plan limits, the body may also include limitReached, upgradeRequired, currentCount, and limit.