Developers

The NxtVybe API

Pull your campaign results and accepted creator content into your own dashboards, reports and tools. The API is currently read-only.

Version: v1Base URL: https://nxtvybe.com/api/v1

Getting started

  1. Sign in to your brand account and open Profile → API keys.
  2. Create a named key and copy the full secret right away.
  3. Send it as a Bearer token on every request.
  4. Call GET /campaigns to list your campaigns.
  5. Call GET /campaigns/:campaignId/submissions to retrieve accepted content.

Authentication

Every request needs a brand API key in the Authorization header:

Header
Authorization: Bearer nxtvybe_live_...

Brands create, view and revoke keys from their dashboard under Profile → API keys. The list shows each key's name, short prefix, creation date and last-used date. Revoked keys stop working immediately.

The full secret is shown only once, when the key is created. NxtVybe stores only a secure hash and can't show it again. Keep keys on your server, never in browser or mobile code, and revoke any key that may have been exposed.

Keys can only read campaigns owned by the brand that created them. Login tokens are not accepted.

List campaigns

GET/api/v1/campaigns

Returns your campaigns, newest first.

ParameterDefaultDescription
status—Optional: draft, active, completed, budget_reached, awaiting_client_approval or paused.
limit20Results per page, 1-100.
offset0Number of results to skip.
curl
curl https://nxtvybe.com/api/v1/campaigns \
  -H "Authorization: Bearer nxtvybe_live_YOUR_KEY"
200 Response
{
  "data": [
    {
      "id": "3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04",
      "title": "Fall Launch",
      "status": "active",
      "campaign_type": "performance",
      "objective": "awareness",
      "total_campaign_budget": 250000,
      "cpm_rate": 300,
      "spent_cents": 48210,
      "estimated_views": 694444,
      "conversion_tracking_enabled": true,
      "primary_conversion_type": "purchase",
      "created_at": "2026-09-12T15:04:11Z",
      "start_date": "2026-09-15",
      "end_date": null
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 1
  }
}

Get a campaign

GET/api/v1/campaigns/:campaignId

Returns one campaign with a performance summary across its submissions. Money values are in cents; cpm_rate is the creator CPM in cents.

curl
curl https://nxtvybe.com/api/v1/campaigns/3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04 \
  -H "Authorization: Bearer nxtvybe_live_YOUR_KEY"
200 Response
{
  "id": "3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04",
  "title": "Fall Launch",
  "status": "active",
  "campaign_type": "performance",
  "objective": "awareness",
  "total_campaign_budget": 250000,
  "cpm_rate": 300,
  "spent_cents": 48210,
  "estimated_views": 694444,
  "conversion_tracking_enabled": true,
  "primary_conversion_type": "purchase",
  "created_at": "2026-09-12T15:04:11Z",
  "start_date": "2026-09-15",
  "end_date": null,
  "performance": {
    "submission_count": 2,
    "published_submission_count": 2,
    "tracked_views": 160700,
    "likes": 11050,
    "comments": 300,
    "shares": 791,
    "conversion_count": 37
  }
}

List campaign submissions

GET/api/v1/campaigns/:campaignId/submissions

Returns only content NxtVybe has accepted (approved, live or bonus pending), newest first.

ParameterDefaultDescription
limit50Results per page, 1-100.
offset0Number of results to skip.
curl
curl "https://nxtvybe.com/api/v1/campaigns/3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04/submissions?limit=50&offset=0" \
  -H "Authorization: Bearer nxtvybe_live_YOUR_KEY"
200 Response
{
  "campaign_id": "3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04",
  "data": [
    {
      "id": "9b2d4e61-7f3a-4c18-b5e0-2a6c8d1f3e97",
      "status": "live",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@creator/video/1",
      "metrics": {
        "views": 120400,
        "likes": 8100,
        "comments": 212,
        "shares": 640
      },
      "submitted_at": "2026-09-18T19:22:05Z",
      "live_at": "2026-09-19T14:00:00Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "offset": 0,
    "total": 1
  }
}

Pagination

List endpoints return a pagination object with limit, offset and the overall total. Increase offset by limit until it reaches total.

Errors

Errors return JSON with a single error message.

400{"error":"limit must be 1-100"}Invalid query parameter (status, limit or offset).
401{"error":"Unauthorized"}Missing, malformed, unknown or revoked API key. Login tokens are not accepted.
403{"error":"Forbidden"}The campaign exists but belongs to another brand.
404{"error":"Campaign not found"}Unknown or malformed campaign ID.
429{"error":"Rate limit exceeded"}Too many requests for this API key. Wait for Retry-After seconds.

Rate limits

Each API key can make 60 requests per minute. Limits are tracked per key, so separate keys have separate limits. Over the limit, the API returns 429 with these headers:

  • Retry-After: seconds until the next window
  • X-RateLimit-Limit: 60
  • X-RateLimit-Remaining: 0

JavaScript example

JavaScript
const API_KEY = process.env.NXTVYBE_API_KEY; // keep keys on your server

async function nxtvybe(path) {
  const res = await fetch(`https://nxtvybe.com/api/v1${path}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  if (res.status === 429) {
    const wait = Number(res.headers.get("Retry-After") ?? 60);
    throw new Error(`Rate limited, retry in ${wait}s`);
  }
  if (!res.ok) throw new Error((await res.json()).error);
  return res.json();
}

const { data: campaigns } = await nxtvybe("/campaigns?status=active");
for (const campaign of campaigns) {
  const { data: submissions } = await nxtvybe(`/campaigns/${campaign.id}/submissions`);
  console.log(campaign.title, submissions.length);
}

What the API does not expose

  • Creator names, emails, user IDs or profile details
  • Creator earnings, payouts or payout status
  • Stripe or other payment-provider IDs
  • NxtVybe fee rates, fee splits or internal budget allocations
  • Shipping addresses and fulfillment details
  • Submissions that NxtVybe has not accepted, plus internal review notes
  • Brand account IDs, legal acceptances and other internal records

A submission's url is the public social post, which shows whatever the post itself shows publicly.

Webhooks

Webhooks push signed event notifications to your HTTPS endpoint when your campaigns or accepted submissions change, so you don't have to poll.

Setup

  1. Open Profile → API keys and scroll to Webhooks.
  2. Name the endpoint, enter its HTTPS URL and pick the events you want.
  3. Copy the signing secret (whsec_…) — it is shown only once and cannot be retrieved later.
  4. Click Send test event to receive a webhook.test delivery.

Events

ParameterDefaultDescription
campaign.createddata.campaignA campaign was created.
campaign.updateddata.campaignCampaign details or status changed (spend updates are not sent).
campaign.starteddata.campaignA campaign became active.
campaign.completeddata.campaignA campaign was completed.
submission.createddata.submissionA submission first became visible through the API (accepted by NxtVybe).
submission.approveddata.submissionNxtVybe approved a submission.
submission.livedata.submissionA submission went live and is being tracked.

Payload

Every delivery is a JSON envelope with id, type, created_at and data. Campaign events carry the same campaign object as GET /campaigns; submission events carry the same submission object as the submissions endpoint. Webhooks never include more than the API.

campaign.started
{
  "id": "6a1f0c3e-2d4b-4e8f-9c7a-1b5d3e7f9a20",
  "type": "campaign.started",
  "created_at": "2026-09-15T16:00:02Z",
  "data": {
    "campaign": {
      "id": "3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04",
      "title": "Fall Launch",
      "status": "active",
      "campaign_type": "performance",
      "objective": "awareness",
      "total_campaign_budget": 250000,
      "cpm_rate": 300,
      "spent_cents": 48210,
      "estimated_views": 694444,
      "conversion_tracking_enabled": true,
      "primary_conversion_type": "purchase",
      "created_at": "2026-09-12T15:04:11Z",
      "start_date": "2026-09-15",
      "end_date": null
    }
  }
}
submission.live
{
  "id": "c4e8a2b6-1f3d-4a5c-8e7b-9d0f2a4c6e81",
  "type": "submission.live",
  "created_at": "2026-09-19T14:00:01Z",
  "data": {
    "campaign_id": "3f6c1a52-8b1e-4c47-9a0d-5e2b7c9d1f04",
    "submission": {
      "id": "9b2d4e61-7f3a-4c18-b5e0-2a6c8d1f3e97",
      "status": "live",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@creator/video/1",
      "metrics": {
        "views": 120400,
        "likes": 8100,
        "comments": 212,
        "shares": 640
      },
      "submitted_at": "2026-09-18T19:22:05Z",
      "live_at": "2026-09-19T14:00:00Z"
    }
  }
}

Headers

  • X-NxtVybe-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>
  • X-NxtVybe-Event-Id / X-NxtVybe-Event-Type / X-NxtVybe-Timestamp
  • X-NxtVybe-Delivery-Attempt

Verifying signatures

The signature is HMAC-SHA256 of `${t}.${rawBody}` using your signing secret. Verify against the exact raw body (before JSON parsing), compare in constant time, and reject timestamps more than 5 minutes old to block replays.

JavaScript (Node / Express)
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.NXTVYBE_WEBHOOK_SECRET; // whsec_...
const TOLERANCE_SECONDS = 5 * 60;

app.post("/webhooks/nxtvybe", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("X-NxtVybe-Signature") ?? "";
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > TOLERANCE_SECONDS) return res.sendStatus(400);

  const rawBody = req.body.toString("utf8");
  const expected = crypto.createHmac("sha256", SECRET).update(`${t}.${rawBody}`).digest("hex");
  const given = Buffer.from(parts.v1 ?? "", "utf8");
  const valid = given.length === expected.length && crypto.timingSafeEqual(given, Buffer.from(expected, "utf8"));
  if (!valid) return res.sendStatus(400);

  const event = JSON.parse(rawBody);
  // Idempotency: skip if event.id was already processed.
  res.sendStatus(200);
});

Responding, retries and idempotency

  • Return any 2xx within 10 seconds. Anything else, a timeout or a network error counts as a failure. Redirects are not followed.
  • Failed deliveries are retried after about 1 min, 5 min, 30 min, 2 hr, 12 hr, then marked failed. You can retry manually from delivery history.
  • The event id and body stay the same on every retry — store processed ids and ignore duplicates.
  • Events may arrive out of order; use created_at if order matters.
  • Deliveries to a disabled endpoint are skipped.

Endpoint requirements

  • HTTPS on the default port, a public hostname (no IP addresses or credentials in the URL).
  • Hosts that resolve to private, loopback, link-local or cloud-metadata addresses are rejected.
  • Up to 10 endpoints per brand.

Use NxtVybe inside Lovable

NxtVybe ships a built-in connector for Lovable, so builders can manage creator marketing without leaving their Lovable project. Once connected, they can ask Lovable to list their campaigns, check posts and earnings — or launch a Creator Content package for the app they just built.

Connect

  1. In Lovable, open Connectors and add a custom MCP connector.
  2. Enter the URL https://nxtvybe.com/mcp.
  3. Sign in with your NxtVybe brand account when prompted to authorize.

What builders can ask for

  • “List my NxtVybe campaigns and how they're performing.”
  • “Show the posts and earnings on my account.”
  • “Launch creator content for my site” — Lovable stages an unpaid First Batch, Momentum or Content Library draft and returns a link to review it and check out on NxtVybe. Nothing is charged inside Lovable.

Everything is scoped to the signed-in brand's own account, and creating a package always ends with review and payment on NxtVybe — never in the chat.

Questions? support@nxtvybe.com · NxtVybe for Brands