Skip to main content
Vortex handles the complete invitation lifecycle — sending invites via email/SMS/share links, tracking clicks and conversions, managing referral programs, and optimizing your invitation flows with A/B testing.

Installation

dotnet add package TeamVortexSoftware.VortexSDK

Quick Start

Generate a secure token for Vortex components
using TeamVortexSoftware.VortexSDK;

var client = new VortexClient(Environment.GetEnvironmentVariable("VORTEX_API_KEY"));

var payload = new GenerateTokenPayload
{
    User = new TokenUser { Id = "user-123", Email = "user@example.com" }
};

var token = client.GenerateToken(payload);

Integration Flow

Vortex uses a split architecture: your backend signs tokens with the SDK, and your frontend renders components that use those tokens to securely interact with Vortex.
1

Install the backend SDK

Add this SDK to your .NET project
dotnet add package TeamVortexSoftware.VortexSDK
2

Initialize the client

Create a Vortex client with your API key (keep this on the server!)
using TeamVortexSoftware.VortexSDK;

var client = new VortexClient(
Environment.GetEnvironmentVariable("VORTEX_API_KEY")
);
3

Generate a token for the current user

When a user loads a page with a Vortex component, generate a signed token on your server
var token = client.GenerateToken(new GenerateTokenPayload
{
User = new TokenUser { Id = currentUser.Id }
});
4

Pass the token to your frontend

Include the token in your page response or API response
return Ok(new { vortexToken = token });
5

Render a Vortex component with the token

Use the React/Angular/Web Component with the token
import { VortexInvite } from "@teamvortexsoftware/vortex-react";

<VortexInvite token={vortexToken} />
6

Vortex handles the rest

The component securely communicates with Vortex servers, displays the invitation UI, sends emails/SMS, tracks conversions, and reports analytics

Methods

Core Methods

GenerateToken()

Generate a signed token for use with Vortex widgets
GenerateToken(GenerateTokenPayload payload, GenerateTokenOptions? options): string
Parameters:
NameTypeRequiredDescription
payloadGenerateTokenPayloadData to sign (user, component, scope, vars, etc.)
optionsGenerateTokenOptions?Optional configuration (ExpiresIn)
Returns: string — Signed JWT token string

GetInvitationAsync()

Get a specific invitation by ID
GetInvitationAsync(string invitationId): Task<Invitation>
Parameters:
NameTypeRequiredDescription
invitationIdstringThe invitation ID
Returns: Task&lt;Invitation&gt; — The invitation details

AcceptInvitationAsync()

Accept a single invitation (recommended method)
AcceptInvitationAsync(string invitationId, AcceptUser user): Task<Invitation>
Parameters:
NameTypeRequiredDescription
invitationIdstringSingle invitation ID to accept
userAcceptUserUser with email or phone (and optional name)
Returns: Task&lt;Invitation&gt; — Invitation result

GetInvitationsByTargetAsync()

Get invitations by target (email or sms)
GetInvitationsByTargetAsync(string targetType, string targetValue): Task<List<Invitation>>
Parameters:
NameTypeRequiredDescription
targetTypestringType of target (email, phone)
targetValuestringThe target value
Returns: Task&lt;List&lt;Invitation&gt;&gt; — List of invitations

RevokeInvitationAsync()

Revoke (delete) an invitation
RevokeInvitationAsync(string invitationId): Task
Parameters:
NameTypeRequiredDescription
invitationIdstringThe invitation ID to revoke
Returns: Task

AcceptInvitationsAsync()

Accept multiple invitations using the new User format (preferred)
AcceptInvitationsAsync(List<string> invitationIds, AcceptUser user): Task<Invitation>
Parameters:
NameTypeRequiredDescription
invitationIdsList&lt;string&gt;List of invitation IDs to accept
userAcceptUserUser with email or phone (and optional name)
Returns: Task&lt;Invitation&gt; — Invitation result

DeleteInvitationsByScopeAsync()

Delete all invitations for a specific scope
DeleteInvitationsByScopeAsync(string groupType, string groupId): Task
Parameters:
NameTypeRequiredDescription
groupTypestringThe scope type (organization, team, etc.)
groupIdstringThe scope identifier
Returns: Task

GetInvitationsByScopeAsync()

Get all invitations for a specific scope
GetInvitationsByScopeAsync(string groupType, string groupId): Task<List<Invitation>>
Parameters:
NameTypeRequiredDescription
groupTypestringThe scope type (organization, team, etc.)
groupIdstringThe scope identifier
Returns: Task&lt;List&lt;Invitation&gt;&gt; — List of invitations for the scope

ReinviteAsync()

Reinvite a user (send invitation again)
ReinviteAsync(string invitationId): Task<Invitation>
Parameters:
NameTypeRequiredDescription
invitationIdstringThe invitation ID to reinvite
Returns: Task&lt;Invitation&gt; — The reinvited invitation result

CreateInvitationAsync()

Create an invitation from your backend. This method allows you to create invitations programmatically using your API key, without requiring a user JWT token. Useful for server-side invitation creation, such as “People You May Know” flows or admin-initiated invitations.
CreateInvitationAsync(CreateInvitationRequest request): Task<CreateInvitationResponse>
Parameters:
NameTypeRequiredDescription
requestCreateInvitationRequestThe create invitation request
Returns: Task&lt;CreateInvitationResponse&gt; — CreateInvitationResponse with id, shortLink, status, and createdAt
// Create an email invitation
var request = new CreateInvitationRequest(
    "widget-config-123",
    CreateInvitationTarget.Email("invitee@example.com"),
    new Inviter("user-456", "inviter@example.com", "John Doe")
);
request.Groups = new List&lt;CreateInvitationScope&gt;
{
    new("team", "team-789", "Engineering")
};
var response = await client.CreateInvitationAsync(request);
// Create an internal invitation (PYMK flow)
var pymkRequest = new CreateInvitationRequest(
    "widget-config-123",
    CreateInvitationTarget.Internal("internal-user-abc"),
    new Inviter("user-456")
);
pymkRequest.Source = "pymk";
var response = await client.CreateInvitationAsync(pymkRequest);

GetAutojoinDomainsAsync()

Get autojoin domains configured for a specific scope
GetAutojoinDomainsAsync(string scopeType, string scope): Task<AutojoinDomainsResponse>
Parameters:
NameTypeRequiredDescription
scopeTypestringThe type of scope (e.g., “organization”, “team”, “project”)
scopestringThe scope identifier (customer’s group ID)
Returns: Task&lt;AutojoinDomainsResponse&gt; — AutojoinDomainsResponse with autojoin domains and invitation

ConfigureAutojoinAsync()

Configure autojoin domains for a specific scope
ConfigureAutojoinAsync(ConfigureAutojoinRequest request): Task<AutojoinDomainsResponse>
Parameters:
NameTypeRequiredDescription
requestConfigureAutojoinRequestThe configure autojoin request
Returns: Task&lt;AutojoinDomainsResponse&gt; — AutojoinDomainsResponse with updated autojoin domains

SyncInternalInvitationAsync()

Sync an internal invitation action (accept or decline)
SyncInternalInvitationAsync(SyncInternalInvitationRequest request): Task<SyncInternalInvitationResponse>
Parameters:
NameTypeRequiredDescription
requestSyncInternalInvitationRequestThe sync internal invitation request
Returns: Task&lt;SyncInternalInvitationResponse&gt; — SyncInternalInvitationResponse with processed count and invitationIds
var request = new SyncInternalInvitationRequest("user-123", "user-456", "accepted", "component-uuid");
var response = await client.SyncInternalInvitationAsync(request);
Console.WriteLine($"Processed: {response.Processed}");

Types

GenerateTokenPayload

Payload for GenerateToken - used to generate secure tokens for Vortex components
FieldTypeRequiredDescription
userTokenUser?The authenticated user who will be using the Vortex component
componentstring?Component ID to generate token for (from your Vortex dashboard)
scopestring?Scope identifier to restrict invitations to a specific team/org (format: “scopeType:scopeId”)
varsDictionary&lt;string, object&gt;?Custom variables to pass to the component for template rendering

TokenUser

User data for GenerateToken - represents the authenticated user sending invitations
FieldTypeRequiredDescription
idstring?Unique identifier for the user in your system. Used to attribute invitations and track referral chains.
namestring?Display name shown to invitation recipients (e.g., “John invited you”)
emailstring?User’s email address. Used for reply-to in invitation emails.
avatarUrlstring?URL to user’s avatar image. Displayed in invitation emails and widgets.
adminScopesList&lt;string&gt;?List of scope IDs where this user has admin privileges (e.g., [“team:team-123”])

AcceptUser

User data for accepting invitations - identifies who accepted the invitation
FieldTypeRequiredDescription
emailstring?Email address of the user accepting. At least one of Email or Phone is required.
phonestring?Phone number with country code (e.g., “+15551234567”). At least one of Email or Phone is required.
namestring?Display name of the accepting user (shown in notifications to inviter)
isExistingbool?Whether user was already registered. true=existing, false=new signup, null=unknown. Used for conversion analytics.

Invitation

Complete invitation details as returned by the Vortex API
FieldTypeRequiredDescription
idstringUnique identifier for this invitation
accountIdstringYour Vortex account ID
clickThroughsintNumber of times the invitation link was clicked
formSubmissionDataDictionary&lt;string, object&gt;?Data submitted through the invitation form, including standard fields and any custom fields configured on your widget.
configurationAttributesDictionary&lt;string, object&gt;?
attributesDictionary&lt;string, object&gt;?Custom attributes attached to this invitation
createdAtstringISO 8601 timestamp when the invitation was created
deactivatedboolWhether this invitation has been revoked or expired
deliveryCountintNumber of times the invitation was sent (including reminders)
deliveryTypesList&lt;DeliveryType&gt;Channels used to deliver this invitation (email, sms, share link)
foreignCreatorIdstringYour internal user ID for the person who created this invitation
invitationTypeInvitationTypeType of invitation: single_use (1:1), multi_use (1:many), or autojoin
modifiedAtstring?ISO 8601 timestamp of last modification
statusInvitationStatusCurrent status: queued, sending, sent, delivered, accepted, shared, unfurled
targetList&lt;InvitationTarget&gt;List of invitation recipients with their contact info and status
viewsintNumber of times the invitation page was viewed
widgetConfigurationIdstringWidget configuration ID used for this invitation
deploymentIdstringDeployment ID this invitation belongs to
groupsList&lt;InvitationScope&gt;Scopes (teams/orgs) this invitation grants access to
acceptsList&lt;InvitationAcceptance&gt;?List of acceptance records if the invitation was accepted (optional)
scopestring?Primary scope identifier (e.g., “team-123”)
scopeTypestring?Type of the primary scope (e.g., “team”, “organization”)
expiredboolWhether this invitation has passed its expiration date
expiresstring?ISO 8601 timestamp when this invitation expires
metadataDictionary&lt;string, object&gt;?Custom metadata attached to this invitation
passThroughstring?Pass-through data returned unchanged in webhooks and callbacks
sourcestring?Source identifier for tracking (e.g., “ios-app”, “web-dashboard”)
subtypestring?Subtype for analytics segmentation (e.g., “pymk”, “find-friends”)
creatorNamestring?Display name of the user who created this invitation
creatorAvatarUrlstring?Avatar URL of the user who created this invitation

InvitationTarget

Represents the target recipient of an invitation
FieldTypeRequiredDescription
typeInvitationTargetTypeDelivery channel: email, phone, share (link), or internal (in-app)
valuestringTarget address: email, phone number with country code, or share link ID
namestring?Display name of the recipient (e.g., “John Doe”)
avatarUrlstring?Avatar URL for the recipient, shown in invitation lists and widgets

InvitationScope

Invitation group from API responses This matches the MemberGroups table structure from the API
FieldTypeRequiredDescription
idstringVortex internal UUID
accountIdstringVortex account ID
groupIdstringCustomer’s group ID (the ID they provided to Vortex)
typestringGroup type (e.g., “workspace”, “team”)
namestringGroup name
createdAtstringISO 8601 timestamp when the group was created

CreateInvitationTarget

Target recipient when creating an invitation
FieldTypeRequiredDescription
typeCreateInvitationTargetTypeEnumDelivery channel: email, phone, or internal (in-app)
valuestringTarget address: email, phone number (with country code), or internal user ID
namestring?Display name of the recipient (shown in invitation emails and UI)
avatarUrlstring?Avatar URL for the recipient (displayed in invitation lists)

Inviter

Information about the user sending the invitation - used for attribution and display
FieldTypeRequiredDescription
userIdstringYour internal user ID for the inviter (required for attribution)
userEmailstring?Inviter’s email address (used for reply-to and identification)
namestring?Display name shown to recipients (e.g., “John invited you to…”)
avatarUrlstring?Avatar URL displayed in invitation emails and widgets

User

User data for JWT generation - represents the authenticated user sending invitations. Only Id is required. Email is optional but recommended for invitation attribution.
FieldTypeRequiredDescription
idstringYour internal user ID (required for invitation attribution)
emailstring?User’s email address (optional, used for reply-to in invitation emails)
namestring?Display name shown to recipients (e.g., “John invited you”)
avatarUrlstring?Avatar URL displayed in invitation emails and widgets (must be HTTPS)
adminScopesList&lt;string&gt;?List of scopes where user has admin privileges (e.g., [“autojoin”])
allowedEmailDomainsList&lt;string&gt;?Restrict invitations to these email domains (e.g., [“acme.com”])

Identifier

Identifier for a user - used in JWT generation to link user across channels
FieldTypeRequiredDescription
typestringIdentifier type: “email”, “phone”, “username”, or custom type
valuestringThe identifier value (email address, phone number, etc.)

Group

Scope/group for JWT generation - defines user’s team/org membership in tokens
FieldTypeRequiredDescription
typestringScope type (e.g., “team”, “organization”, “workspace”)
idstring?Legacy scope identifier. Use Scope/groupId instead.
groupIdstring?Your internal scope/group identifier (preferred)
namestringDisplay name for the scope (e.g., “Engineering Team”)

InvitationAcceptance

Record of an invitation being accepted
FieldTypeRequiredDescription
idstringUnique identifier for this acceptance record
accountIdstringYour Vortex account ID
acceptedAtstringISO 8601 timestamp when the invitation was accepted
targetInvitationTarget?The target that accepted the invitation

CreateInvitationScope

Group information for creating invitations
FieldTypeRequiredDescription
typestringGroup type (e.g., “team”, “organization”)
groupIdstringYour internal group ID
namestringDisplay name of the group

UnfurlConfig

Configuration for link unfurl (Open Graph) metadata. Controls how the invitation link appears when shared on social platforms or messaging apps.
FieldTypeRequiredDescription
titlestring?The title shown in link previews (og:title)
descriptionstring?The description shown in link previews (og:description)
imagestring?The image URL shown in link previews (og:image) - must be HTTPS
typestring?The Open Graph type (og:type) - e.g., ‘website’, ‘article’, ‘product’
siteNamestring?The site name shown in link previews (og:site_name)

AutojoinDomain

Autojoin domain - users with matching email domains automatically join the scope
FieldTypeRequiredDescription
idstringUnique identifier for this autojoin configuration
domainstringEmail domain that triggers autojoin (e.g., “acme.com”)

Webhooks

Webhooks let your server receive real-time notifications when events happen in Vortex. Use them to sync invitation state with your database, trigger onboarding flows, update your CRM, or send internal notifications.

Setup

  1. Go to your Vortex dashboard → Integrations → Webhooks tab
  2. Click “Add Webhook”
  3. Enter your endpoint URL (must be HTTPS in production)
  4. Copy the signing secret — you’ll use this to verify webhook signatures
  5. Select which events you want to receive

Example

ASP.NET Core webhook handler
using TeamVortexSoftware.VortexSDK;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("webhooks")]
public class WebhookController : ControllerBase
{
    private readonly VortexWebhooks _webhooks = new(
        Environment.GetEnvironmentVariable("VORTEX_WEBHOOK_SECRET")
    );

    [HttpPost("vortex")]
    public IActionResult HandleWebhook(
        [FromBody] string body,
        [FromHeader(Name = "X-Vortex-Signature")] string signature)
    {
        // Verify the signature
        if (!_webhooks.VerifySignature(body, signature))
            return BadRequest("Invalid signature");

        // Parse the event
        var webhookEvent = _webhooks.ParseEvent(body);

        switch (webhookEvent.Type)
        {
            case "invitation.accepted":
                // User accepted an invitation — activate their account
                Console.WriteLine($"Accepted: {webhookEvent.Data}");
                break;
            case "member.created":
                // New member joined via invitation
                Console.WriteLine($"New member: {webhookEvent.Data}");
                break;
        }

        return Ok(new { received = true });
    }
}

Events

EventDescription
invitation.createdA new invitation was created
invitation.acceptedAn invitation was accepted by the recipient
invitation.deactivatedAn invitation was deactivated (revoked or expired)
invitation.email.deliveredInvitation email was successfully delivered
invitation.email.bouncedInvitation email bounced (invalid address)
invitation.email.openedRecipient opened the invitation email
invitation.link.clickedRecipient clicked the invitation link
invitation.reminder.sentA reminder email was sent for a pending invitation
member.createdA new member was created from an accepted invitation
group.member.addedA member was added to a scope/group
deployment.createdA new deployment configuration was created
deployment.deactivatedA deployment was deactivated
abtest.startedAn A/B test was started
abtest.winner_declaredAn A/B test winner was declared
email.complainedRecipient marked the email as spam

Use Cases

  • Activate users on acceptance — When invitation.accepted fires, mark the user as active in your database and trigger your onboarding flow.
  • Track invitation performance — Monitor email.delivered, email.opened, and link.clicked events to measure invitation funnel metrics.
  • Sync team membership — Use member.created and group.member.added to keep your internal membership records in sync.
  • Alert on delivery issues — Watch for email.bounced events to proactively reach out via alternative channels.

Error Handling

ErrorDescription
VortexExceptionThrown for validation errors (e.g., missing API key, invalid parameters) or API failures

Resources