Docs / Utvecklare
REST API
Använd tenant-API-nycklar från ert CMS eller backend. Dashboard-sessioncookies är bara för EngageNudge-appen. Anropa API:t från er server. Lägg aldrig nyckeln i webbläsaren.
| Bas-URL | https://api.engagenudge.com |
| Auth | Authorization: Bearer en_… |
| Content type | application/json |
Skapa en API-nyckel
- Dashboard → Integrationer → REST API
- Som tenant-ägare, skapa en nyckel och kopiera hemligheten en gång (
en_…) - Spara den i er secret manager. Den visas aldrig igen.
Nyckelhantering (dashboard-session / ägare only):
| Method | Path |
|---|---|
GET | /v1/tenants/:tenantId/api-keys |
POST | /v1/tenants/:tenantId/api-keys body { "name": "CMS production" } |
DELETE | /v1/tenants/:tenantId/api-keys/:keyId |
Auth
Authorization: Bearer en_YOUR_API_KEYNyckelns tenant måste matcha kampanjens tenant. Logga inte rånyckeln. Ni behöver också tenant-id och sajt-id (UUID) från install-snippeten.
Rekommenderat flöde
(valfritt) POST /v1/content/preview
POST /v1/tenants/:tenantId/campaigns → campaignId (draft)
POST /v1/campaigns/:campaignId/test → bara testenheter
eller POST /v1/campaigns/:campaignId/send → live-publik
eller POST /v1/campaigns/:campaignId/schedule → scheduleAt (ISO-8601)Live-utskick kräver accepterad DPA, att utskick inte är pausade, att billing tillåter publiken, och en skickbar kampanjstatus (oftast draft). Test kräver minst en testprenumerant.
Preview
curl -X POST "https://api.engagenudge.com/v1/content/preview" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{
"url": "https://publisher.example/story",
"siteId": "'"$SITE_ID"'",
"tenantId": "'"$TENANT_ID"'"
}'url krävs (HTTPS, SSRF-säker hämtning). siteId och tenantId gör beslutet publikmedvetet.
Skapa kampanj
curl -X POST "https://api.engagenudge.com/v1/tenants/$TENANT_ID/campaigns" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{
"siteId": "'"$SITE_ID"'",
"url": "https://publisher.example/story",
"imageUrl": "https://publisher.example/image.jpg"
}'| Fält | Krävs | Anteckning |
|---|---|---|
siteId | ja | UUID på tenant |
url | ja | Destinations- / artikel-URL |
mode | nej | "url" eller "manual" |
title / body | manual | Max 120 / 240 tecken |
imageUrl | nej | HTTPS-URL, eller "" för att rensa |
topicIds | nej | Topic-UUID-filter |
forceSend | nej | URL-läge: skapa skickbart utkast även vid skip. RSS auto-push sätter det bara för ett flöde med åsidosättning påslagen. |
Utan forceSend kan en avvisad artikel landa som cancelled. Dashboard-komponering skickar forceSend: true så redaktörer kan publicera.
JSON-svaret innehåller campaignId. Använd det id:t för test, skicka eller schemalägg.
Exempel
Skapa en kampanj och skicka den. Samma sökväg och headers i varje språk. Läs API_KEY, TENANT_ID och SITE_ID från er miljö. Hårdkoda inte hemligheten.
JavaScript
const API_URL = "https://api.engagenudge.com";
const API_KEY = process.env.ENGAGENUDGE_API_KEY;
const TENANT_ID = process.env.ENGAGENUDGE_TENANT_ID;
const SITE_ID = process.env.ENGAGENUDGE_SITE_ID;
const created = await fetch(`${API_URL}/v1/tenants/${TENANT_ID}/campaigns`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
siteId: SITE_ID,
url: "https://publisher.example/story",
imageUrl: "https://publisher.example/image.jpg",
}),
});
if (!created.ok) {
throw new Error(`Create failed: ${created.status} ${await created.text()}`);
}
const { campaignId } = await created.json();
const sent = await fetch(`${API_URL}/v1/campaigns/${campaignId}/send`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
},
});
if (!sent.ok) {
throw new Error(`Send failed: ${sent.status} ${await sent.text()}`);
}TypeScript
const API_URL = "https://api.engagenudge.com";
type CampaignCreated = { campaignId: string };
async function createAndSendNudge(input: {
apiKey: string;
tenantId: string;
siteId: string;
url: string;
imageUrl?: string;
}): Promise<CampaignCreated> {
const created = await fetch(`${API_URL}/v1/tenants/${input.tenantId}/campaigns`, {
method: "POST",
headers: {
Authorization: `Bearer ${input.apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
siteId: input.siteId,
url: input.url,
imageUrl: input.imageUrl,
}),
});
if (!created.ok) {
throw new Error(`Create failed: ${created.status} ${await created.text()}`);
}
const campaign = (await created.json()) as CampaignCreated;
const sent = await fetch(`${API_URL}/v1/campaigns/${campaign.campaignId}/send`, {
method: "POST",
headers: {
Authorization: `Bearer ${input.apiKey}`,
"Idempotency-Key": crypto.randomUUID(),
},
});
if (!sent.ok) {
throw new Error(`Send failed: ${sent.status} ${await sent.text()}`);
}
return campaign;
}Python
import json
import os
import uuid
import urllib.error
import urllib.request
API_URL = "https://api.engagenudge.com"
API_KEY = os.environ["ENGAGENUDGE_API_KEY"]
TENANT_ID = os.environ["ENGAGENUDGE_TENANT_ID"]
SITE_ID = os.environ["ENGAGENUDGE_SITE_ID"]
def request(method: str, path: str, payload: dict | None = None, extra_headers: dict | None = None) -> dict:
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
**(extra_headers or {}),
}
data = None if payload is None else json.dumps(payload).encode()
req = urllib.request.Request(f"{API_URL}{path}", data=data, headers=headers, method=method)
try:
with urllib.request.urlopen(req) as res:
body = res.read().decode()
return json.loads(body) if body else {}
except urllib.error.HTTPError as exc:
raise RuntimeError(f"{method} {path} failed: {exc.code} {exc.read().decode()}") from exc
campaign = request(
"POST",
f"/v1/tenants/{TENANT_ID}/campaigns",
{
"siteId": SITE_ID,
"url": "https://publisher.example/story",
"imageUrl": "https://publisher.example/image.jpg",
},
)
request(
"POST",
f"/v1/campaigns/{campaign['campaignId']}/send",
extra_headers={"Idempotency-Key": str(uuid.uuid4())},
)PHP
<?php
$apiUrl = 'https://api.engagenudge.com';
$apiKey = getenv('ENGAGENUDGE_API_KEY');
$tenantId = getenv('ENGAGENUDGE_TENANT_ID');
$siteId = getenv('ENGAGENUDGE_SITE_ID');
function en_request(string $method, string $url, string $apiKey, ?array $payload = null, array $extraHeaders = []): array {
$headers = array_merge([
"Authorization: Bearer $apiKey",
'Content-Type: application/json',
], $extraHeaders);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $payload === null ? null : json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
throw new RuntimeException("$method $url failed: $status $body");
}
return $body ? json_decode($body, true) : [];
}
$campaign = en_request('POST', "$apiUrl/v1/tenants/$tenantId/campaigns", $apiKey, [
'siteId' => $siteId,
'url' => 'https://publisher.example/story',
'imageUrl' => 'https://publisher.example/image.jpg',
]);
en_request(
'POST',
"$apiUrl/v1/campaigns/{$campaign['campaignId']}/send",
$apiKey,
null,
['Idempotency-Key: ' . bin2hex(random_bytes(16))]
);Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
static String jsonField(String json, String field) {
String key = "\"" + field + "\"";
int at = json.indexOf(key);
if (at < 0) throw new IllegalStateException(field + " missing: " + json);
int colon = json.indexOf(':', at + key.length());
int start = json.indexOf('"', colon + 1) + 1;
return json.substring(start, json.indexOf('"', start));
}
String apiUrl = "https://api.engagenudge.com";
String apiKey = System.getenv("ENGAGENUDGE_API_KEY");
String tenantId = System.getenv("ENGAGENUDGE_TENANT_ID");
String siteId = System.getenv("ENGAGENUDGE_SITE_ID");
HttpClient client = HttpClient.newHttpClient();
String createJson = """
{
"siteId": "%s",
"url": "https://publisher.example/story",
"imageUrl": "https://publisher.example/image.jpg"
}
""".formatted(siteId);
HttpResponse<String> created = client.send(
HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/v1/tenants/" + tenantId + "/campaigns"))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(createJson))
.build(),
HttpResponse.BodyHandlers.ofString());
if (created.statusCode() < 200 || created.statusCode() >= 300) {
throw new IllegalStateException("Create failed: " + created.statusCode() + " " + created.body());
}
String campaignId = jsonField(created.body(), "campaignId");
HttpResponse<String> sent = client.send(
HttpRequest.newBuilder()
.uri(URI.create(apiUrl + "/v1/campaigns/" + campaignId + "/send"))
.header("Authorization", "Bearer " + apiKey)
.header("Idempotency-Key", UUID.randomUUID().toString())
.POST(HttpRequest.BodyPublishers.noBody())
.build(),
HttpResponse.BodyHandlers.ofString());
if (sent.statusCode() < 200 || sent.statusCode() >= 300) {
throw new IllegalStateException("Send failed: " + sent.statusCode() + " " + sent.body());
}C# (.NET)
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
const string apiUrl = "https://api.engagenudge.com";
var apiKey = Environment.GetEnvironmentVariable("ENGAGENUDGE_API_KEY");
var tenantId = Environment.GetEnvironmentVariable("ENGAGENUDGE_TENANT_ID");
var siteId = Environment.GetEnvironmentVariable("ENGAGENUDGE_SITE_ID");
using var client = new HttpClient { BaseAddress = new Uri(apiUrl) };
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
var created = await client.PostAsJsonAsync(
$"/v1/tenants/{tenantId}/campaigns",
new
{
siteId,
url = "https://publisher.example/story",
imageUrl = "https://publisher.example/image.jpg",
});
created.EnsureSuccessStatusCode();
using var createdJson = JsonDocument.Parse(await created.Content.ReadAsStringAsync());
var campaignId = createdJson.RootElement.GetProperty("campaignId").GetString();
using var sendRequest = new HttpRequestMessage(HttpMethod.Post, $"/v1/campaigns/{campaignId}/send");
sendRequest.Headers.TryAddWithoutValidation("Idempotency-Key", Guid.NewGuid().ToString());
var sent = await client.SendAsync(sendRequest);
sent.EnsureSuccessStatusCode();Test, skicka, schemalägg
curl -X POST "https://api.engagenudge.com/v1/campaigns/$CAMPAIGN_ID/test" \
-H "Authorization: Bearer $API_KEY"
curl -X POST "https://api.engagenudge.com/v1/campaigns/$CAMPAIGN_ID/send" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: optional-unique-key"
curl -X POST "https://api.engagenudge.com/v1/campaigns/$CAMPAIGN_ID/schedule" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_KEY" \
-d '{ "scheduleAt": "2026-08-10T09:00:00.000Z" }'scheduleAt måste vara ISO-8601 i framtiden. Idempotent replay returnerar "duplicate": true.
Vanliga fel
| Status | Kod | Betydelse |
|---|---|---|
| 401 | - | Saknad eller ogiltig API-nyckel |
| 403 | dpa_required | Acceptera DPA i Inställningar |
| 402 | billing | Plan eller publikkap blockerad |
| 409 | illegal_transition | Kampanjen är inte skickbar |
| 423 | send_paused | Paus på sajt eller tenant |
Stoppa en pågående körning från dashboarden eller POST /v1/runs/:runId/stop.
Inte i det här API:t än
- Publicerad OpenAPI
- Utgående webhooks
- Live CMS HMAC-ingest (dashboarden visar bara avsedd payload)
- Subscriber CRUD bortom utskicksvägen