Skip to main content

Partner Authentication

Partner authentication enables you to manage communications for multiple customers using a single set of partner-level credentials. This is ideal for service providers and integration partners who work with multiple organizations.

When to Use Partner Authentication

Use partner authentication when:

  • Multi-Customer Platform: You're building a platform that serves multiple organizations
  • Service Provider: You offer communication services to multiple customers
  • Integration Partner: You're a certified partner managing multiple client accounts
  • Centralized Management: You need to manage communications across multiple customers from a single system

How It Works

Partner authentication combines your partner credentials with customer-specific information:

  • Partner Key: Your unique partner identifier (provided during partner registration)
  • Style Class: Partner branding identifier (typically your company name)
  • Customer ID: The specific customer account you're sending for
  • Customer API Key: The customer's authentication token

Authentication Flow

  1. Partner Registration: Receive your PartnerKey during the partner onboarding process
  2. Customer Authorization: Customers authorize your partner account to send on their behalf
  3. API Requests: Include both partner and customer credentials in each request

Implementation

Request Structure

POST /api/SendMessage_V3/PartnerRoute
Host: m5api.groupcall.com
Content-Type: application/json

{
"PartnerKey": "{YOUR_PARTNER_KEY}",
"styleClass": "{YOUR_COMPANY_NAME}",
"messageData": [
{
"CustomerId": "{CUSTOMER_ID}",
"Password": "{CUSTOMER_API_KEY}",
"SMSMessage": "Your message content here",
"Recipients": [...]
}
]
}

Required Fields

FieldLocationDescriptionExample
PartnerKeyRoot payloadYour unique partner identifier"partner-abc-12345"
styleClassRoot payloadPartner branding identifier"YourCompanyName"
CustomerIdmessageData arrayCustomer's unique ID"1469"
PasswordmessageData arrayCustomer's API key"customer-api-key-67890"

Complete Example

{
"PartnerKey": "partner-abc-12345",
"styleClass": "YourCompanyName",
"messageData": [
{
"CustomerId": "1469",
"Password": "customer-api-key-67890",
"ClientRef": "MSG-12345",
"SMSMessage": "Hello from the Communications API!",
"Recipients": [
{
"MobileNumber": "+447700900123"
}
]
}
]
}
Authentication Method

Partner authentication uses payload-based credentials. Both partner and customer credentials are included in the request body rather than in headers. No Authorization header is required.

Partner vs Customer Authentication

Partner Authentication Benefits

  • Unified Management: Manage multiple customers from a single integration
  • Centralized Billing: Consolidated invoicing across all customers
  • Brand Consistency: Your branding appears in the customer interface
  • Simplified Integration: Single codebase serves multiple customers

When Each Method is Appropriate

ScenarioPartner AuthCustomer Auth
Multi-tenant platform✅ Recommended❌ Complex
Single customer integration❌ Overkill✅ Recommended
Service provider business✅ Required❌ Not available
Direct customer relationship⚠️ Possible✅ Preferred

Security Considerations

Credential Protection

// Example: Secure credential management
const config = {
partnerKey: process.env.COMMUNICATIONS_PARTNER_KEY,
styleClass: process.env.COMMUNICATIONS_STYLE_CLASS,
// Customer credentials retrieved securely per request
};

async function sendMessage(customerId, customerApiKey, messageData) {
const payload = {
PartnerKey: config.partnerKey,
styleClass: config.styleClass,
messageData: [{
CustomerId: customerId,
Password: customerApiKey,
...messageData
}]
};

// Send request...
}

Best Practices

Partner Key Management

  • Environment Variables: Store partner keys in secure environment configuration
  • Access Control: Limit which systems/users can access partner credentials
  • Monitoring: Track partner key usage and detect anomalies
  • Rotation: Coordinate with VenturEd for periodic partner key rotation

Customer Credential Handling

  • Secure Storage: Encrypt customer API keys in your database
  • Scope Limitation: Only access credentials for authorized customers
  • Audit Logging: Log all API calls with customer context
  • Compliance: Follow data protection regulations for credential storage

Request Security

  • HTTPS Only: All requests must use HTTPS encryption
  • Rate Limiting: Implement client-side rate limiting per customer
  • Error Handling: Don't expose credentials in error logs or responses
  • Timeouts: Set appropriate request timeouts

Implementation Examples

Node.js/JavaScript

class CommunicationsPartnerClient {
constructor(partnerKey, styleClass) {
this.partnerKey = partnerKey;
this.styleClass = styleClass;
this.API_BASE = 'https://m5api.groupcall.com';
}

async sendSMS(customerId, customerApiKey, messageData) {
const payload = {
PartnerKey: this.partnerKey,
styleClass: this.styleClass,
messageData: [{
CustomerId: customerId,
Password: customerApiKey,
SMSMessage: messageData.message,
Recipients: messageData.recipients.map(number => ({
MobileNumber: number
})),
ClientRef: messageData.clientRef,
CallbackUrl: messageData.callbackUrl
}]
};

try {
const response = await fetch(`${this.API_BASE}/api/SendMessage_V3/PartnerRoute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});

const result = await response.json();
return this.parseResponse(result);
} catch (error) {
throw new Error(`SMS sending failed: ${error.message}`);
}
}

parseResponse(response) {
if (!Array.isArray(response) || response.length === 0) {
throw new Error('Invalid response format');
}

const result = response[0];

if (result.errorMsg && result.errorMsg.startsWith('OK') && result.MessageId) {
return {
success: true,
messageId: result.MessageId,
status: result.statusMsg,
timestamp: result.transmitDateTime
};
}

const errorMsg = result.errorMsg ||
(result.WarningMessages && result.WarningMessages[0]) ||
'Unknown error';
throw new Error(errorMsg);
}
}

// Usage
const client = new CommunicationsPartnerClient(
process.env.PARTNER_KEY,
process.env.STYLE_CLASS
);

await client.sendSMS('1469', 'customer-api-key', {
message: 'Hello from our platform!',
recipients: ['+447700900123'],
clientRef: 'PLATFORM-MSG-123',
callbackUrl: 'https://platform.com/sms-callback'
});

Python

import requests
import json
import os
from typing import List, Dict, Any

class CommunicationsPartnerClient:
def __init__(self, partner_key: str, style_class: str):
self.partner_key = partner_key
self.style_class = style_class
self.API_BASE = 'https://m5api.groupcall.com'

def send_sms(self, customer_id: str, customer_api_key: str,
message_data: Dict[str, Any]) -> Dict[str, Any]:
payload = {
'PartnerKey': self.partner_key,
'styleClass': self.style_class,
'messageData': [{
'CustomerId': customer_id,
'Password': customer_api_key,
'SMSMessage': message_data['message'],
'Recipients': [
{'MobileNumber': number}
for number in message_data['recipients']
],
'ClientRef': message_data.get('client_ref'),
'CallbackUrl': message_data.get('callback_url')
}]
}

try:
response = requests.post(
f'{self.API_BASE}/api/SendMessage_V3/PartnerRoute',
headers={'Content-Type': 'application/json'},
json=payload,
timeout=30
)
response.raise_for_status()
return self._parse_response(response.json())
except requests.RequestException as e:
raise Exception(f'SMS sending failed: {str(e)}')

def _parse_response(self, response: List[Dict]) -> Dict[str, Any]:
if not response or not isinstance(response, list):
raise Exception('Invalid response format')

result = response[0]

if (result.get('errorMsg', '').startswith('OK') and
result.get('MessageId')):
return {
'success': True,
'message_id': result['MessageId'],
'status': result.get('statusMsg'),
'timestamp': result.get('transmitDateTime')
}

error_msg = (result.get('errorMsg') or
(result.get('WarningMessages', [{}])[0] if result.get('WarningMessages') else None) or
'Unknown error')
raise Exception(error_msg)

# Usage
client = CommunicationsPartnerClient(
os.getenv('PARTNER_KEY'),
os.getenv('STYLE_CLASS')
)

result = client.send_sms('1469', 'customer-api-key', {
'message': 'Hello from our platform!',
'recipients': ['+447700900123'],
'client_ref': 'PLATFORM-MSG-123',
'callback_url': 'https://platform.com/sms-callback'
})

C#

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class CommunicationsPartnerClient
{
private readonly HttpClient _httpClient;
private readonly string _partnerKey;
private readonly string _styleClass;
private readonly string _API_BASE = "https://m5api.groupcall.com";

public CommunicationsPartnerClient(string partnerKey, string styleClass)
{
_partnerKey = partnerKey;
_styleClass = styleClass;
_httpClient = new HttpClient();
}

public async Task<SmsResult> SendSmsAsync(string customerId, string customerApiKey,
SmsMessageData messageData)
{
var payload = new
{
PartnerKey = _partnerKey,
styleClass = _styleClass,
messageData = new[]
{
new
{
CustomerId = customerId,
Password = customerApiKey,
SMSMessage = messageData.Message,
Recipients = messageData.Recipients.Select(r => new { MobileNumber = r }),
ClientRef = messageData.ClientRef,
CallbackUrl = messageData.CallbackUrl
}
}
};

var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");

try
{
var response = await _httpClient.PostAsync($"{_API_BASE}/api/SendMessage_V3/PartnerRoute", content);
response.EnsureSuccessStatusCode();

var responseJson = await response.Content.ReadAsStringAsync();
var results = JsonSerializer.Deserialize<SmsApiResponse[]>(responseJson);

return ParseResponse(results);
}
catch (Exception ex)
{
throw new Exception($"SMS sending failed: {ex.Message}", ex);
}
}

private SmsResult ParseResponse(SmsApiResponse[] response)
{
if (response == null || response.Length == 0)
throw new Exception("Invalid response format");

var result = response[0];

if (!string.IsNullOrEmpty(result.ErrorMsg) &&
result.ErrorMsg.StartsWith("OK") &&
!string.IsNullOrEmpty(result.MessageId))
{
return new SmsResult
{
Success = true,
MessageId = result.MessageId,
Status = result.StatusMsg,
Timestamp = result.TransmitDateTime
};
}

var errorMsg = result.ErrorMsg ??
result.WarningMessages?.FirstOrDefault() ??
"Unknown error";
throw new Exception(errorMsg);
}
}

public class SmsMessageData
{
public string Message { get; set; }
public List<string> Recipients { get; set; }
public string ClientRef { get; set; }
public string CallbackUrl { get; set; }
}

public class SmsResult
{
public bool Success { get; set; }
public string MessageId { get; set; }
public string Status { get; set; }
public DateTime? Timestamp { get; set; }
}

// Usage
var client = new CommunicationsPartnerClient(
Environment.GetEnvironmentVariable("PARTNER_KEY"),
Environment.GetEnvironmentVariable("STYLE_CLASS")
);

var result = await client.SendSmsAsync("1469", "customer-api-key", new SmsMessageData
{
Message = "Hello from our platform!",
Recipients = new List<string> { "+447700900123" },
ClientRef = "PLATFORM-MSG-123",
CallbackUrl = "https://platform.com/sms-callback"
});

Error Handling

Common Partner Authentication Errors

Invalid Partner Key

{
"WarningMessages": ["Partner key is not valid"],
"errorMsg": "Partner key is not valid",
"MessageSentId": 0,
"MessageId": null
}

Solutions:

  • Verify partner key matches the value provided during registration
  • Ensure no extra spaces or characters in the partner key
  • Contact support if key appears correct but still fails

Partner Not Enabled

{
"WarningMessages": ["Partner is not enabled, no message was sent."],
"errorMsg": "Partner is not enabled, no message was sent.",
"MessageSentId": 0,
"MessageId": null
}

Solutions:

  • Complete partner onboarding process
  • Ensure partner account is activated
  • Contact support to enable partner account

Customer Not Authorized for Partner

{
"WarningMessages": ["Customer does not allow sending SMS"],
"errorMsg": null,
"MessageSentId": 0,
"MessageId": null
}

Solutions:

  • Verify customer has authorized your partner account
  • Check customer permissions and access levels
  • Complete customer authorization process

Testing Partner Authentication

Development Environment

// Test configuration
const testConfig = {
partnerKey: 'test-partner-key-12345',
styleClass: 'TestCompany',
testCustomerId: 'test-customer-123',
testCustomerApiKey: 'test-api-key-67890'
};

// Test message
const testMessage = {
message: 'Test message from partner integration',
recipients: ['+447700900123'], // Use your test number
clientRef: 'TEST-' + Date.now(),
callbackUrl: 'https://your-test-endpoint.com/callback'
};

// Send test message
try {
const result = await client.sendSMS(
testConfig.testCustomerId,
testConfig.testCustomerApiKey,
testMessage
);
console.log('Test message sent:', result);
} catch (error) {
console.error('Test failed:', error.message);
}

Partner Onboarding Process

Steps to Become a Partner

  1. Application: Submit partner application to VenturEd
  2. Approval: Complete partner approval process
  3. Credentials: Receive partner key and setup instructions
  4. Testing: Test integration in sandbox environment
  5. Go Live: Move to production after successful testing

Customer Authorization

Each customer must authorize your partner account:

  1. Customer Signup: Customer registers for your service
  2. Authorization Request: Redirect customer to VenturEd authorization flow
  3. Permission Grant: Customer grants permissions to your partner account
  4. Credential Exchange: Receive customer API credentials
  5. Integration Active: Begin sending messages for authorized customer
Complete Code Examples

For detailed implementation examples and troubleshooting, see our Authentication Code Examples guide.


Next Steps: