Getting Started
Azotte gives your team one REST API surface for customer, subscription, bundle, entitlement, and event-driven workflows. Your application stays in control of signup, access, billing decisions, and downstream automation while Azotte handles the subscription orchestration layer behind it.
This page covers the minimum setup for a first integration: which environment to use, what credentials you need, where to create API keys, how to configure event delivery, and which headers every request must include.
How Azotte Fits Into Your Integration
Azotte sits between your product and the operational complexity of subscription commerce.
Typical integration flow:
- Your application collects customer input or triggers a business action.
- Your backend calls the Azotte REST API.
- Azotte stores and processes subscription data in the context of your project.
- Azotte sends subscription and payment events back to your systems through webhooks or Kafka.
Use Azotte when you need one platform to coordinate customers, bundles, subscriptions, entitlements, storefronts, and lifecycle events without spreading that logic across multiple services.
REST API and Environments
Azotte exposes the same API model in two isolated environments:
- Sandbox for development, testing, and QA
- Live for production traffic and real customer operations
Start in Sandbox. Move to Live only after your API calls, event handling, and operational monitoring are verified.
Base URLs
Use the project-specific host that Azotte provisions for your tenant.
Live: https://{projectName}.azotte.com/api/{version}/
Sandbox: https://{projectName}.sandbox.azotte.com/api/{version}/
Example with version v1:
https://acme.azotte.com/api/v1/
https://acme.sandbox.azotte.com/api/v1/
Environment Rules
- Sandbox and Live are fully separated
- API keys are environment-specific and cannot be reused across environments
- Event delivery endpoints should also be separated by environment
- Test your full request and event flow in Sandbox before switching to Live
For a deeper environment guide, see Environments: Sandbox and Live.
Prerequisites
Before you start integrating, make sure you have:
- An Azotte Sandbox project
- Access to the project subdomain for your Sandbox environment
- A backend service that can call the Azotte REST API over HTTPS
- A secure place to store API keys, such as environment variables or a secret manager
- A webhook endpoint or Kafka consumer ready to receive Azotte events
- A clear decision on which system is the source of truth for customer identity
If you do not have a Sandbox project yet, start with your Sandbox signup flow here:
After signup, you should be able to access your project host in this format:
https://{projectName}.sandbox.azotte.com/
Create an API Key
Generate your first API key from your Sandbox project settings:
https://{projectName}.sandbox.azotte.com/settings/integrations/api-keys
Recommended setup:
- Create the key in Sandbox first.
- Store it in your backend secret store.
- Keep separate keys for Sandbox and Live.
- Never expose secret keys in browser code or mobile apps.
Use this key in the x-api-key header for every API request.
For broader key management guidance, see API Keys and Authentication.
Configure Event Delivery
Azotte can push lifecycle events back to your systems so your product stays synchronized when subscriptions, payments, or customer records change.
Configure event delivery here:
https://{projectName}.sandbox.azotte.com/settings/integrations/event-delivery
You can choose one of these delivery patterns:
- Webhooks when you want direct HTTPS callbacks into your application
- Kafka when your platform already processes integration events through a streaming pipeline
Use a separate event destination for Sandbox and Live. That keeps test traffic away from production consumers and makes troubleshooting much simpler.
For webhook-specific details, see Webhooks Overview.
Required Request Headers
Every server-to-server API request needs a small, predictable set of headers.
x-api-key
Authenticates your application.
- Required on every request
- Generated in your project settings
- Must be kept secret when it grants write access
x-tn
Identifies the tenant or project context for the request.
- Required on every request
- Keeps data isolated inside the correct Azotte project
- Should match the tenant context assigned to your integration
Content-Type: application/json
Declares that your request body is JSON.
- Required for requests with a body
- Use the exact value
application/json
Example Request
The example below requests available bundles from the Sandbox environment. It uses the same tenant and API key headers you provided, with a context payload for the offer/bundles endpoint.
- cURL
- Node.js
- Java
- Python
- PHP
- Ruby
- .NET
- Go
curl --location 'https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles' \
--header 'Content-Type: application/Json' \
--header 'x-tn: e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f' \
--header 'x-api-key: sk_dev_acme_sample_123456789' \
-d '{
"context": {
"customerUrn": "sb.00.195",
"customerIpAddress": "84.118.92.180",
"promotionCode": "CMP1WKWAFY",
"interactionType": 10,
"channel": 101
}
}'
const payload = {
context: {
customerUrn: 'sb.00.195',
customerIpAddress: '84.118.92.180',
promotionCode: 'CMP1WKWAFY',
interactionType: 10,
channel: 101
}
};
const response = await fetch('https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles', {
method: 'POST',
headers: {
'Content-Type': 'application/Json',
'x-tn': 'e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f',
'x-api-key': 'sk_dev_acme_sample_123456789'
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log(data);
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
String payload = """
{
\"context\": {
\"customerUrn\": \"sb.00.195\",
\"customerIpAddress\": \"84.118.92.180\",
\"promotionCode\": \"CMP1WKWAFY\",
\"interactionType\": 10,
\"channel\": 101
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles"))
.header("Content-Type", "application/Json")
.header("x-tn", "e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f")
.header("x-api-key", "sk_dev_acme_sample_123456789")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
import requests
payload = {
"context": {
"customerUrn": "sb.00.195",
"customerIpAddress": "84.118.92.180",
"promotionCode": "CMP1WKWAFY",
"interactionType": 10,
"channel": 101
}
}
headers = {
"Content-Type": "application/Json",
"x-tn": "e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f",
"x-api-key": "sk_dev_acme_sample_123456789"
}
response = requests.post(
"https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles",
json=payload,
headers=headers,
timeout=30
)
print(response.json())
<?php
$payload = [
'context' => [
'customerUrn' => 'sb.00.195',
'customerIpAddress' => '84.118.92.180',
'promotionCode' => 'CMP1WKWAFY',
'interactionType' => 10,
'channel' => 101,
],
];
$ch = curl_init('https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/Json',
'x-tn: e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f',
'x-api-key: sk_dev_acme_sample_123456789',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
require 'net/http'
require 'json'
require 'uri'
uri = URI('https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles')
payload = {
context: {
customerUrn: 'sb.00.195',
customerIpAddress: '84.118.92.180',
promotionCode: 'CMP1WKWAFY',
interactionType: 10,
channel: 101
}
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/Json'
request['x-tn'] = 'e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f'
request['x-api-key'] = 'sk_dev_acme_sample_123456789'
request.body = JSON.generate(payload)
response = http.request(request)
puts response.body
using System.Net.Http;
using System.Text;
using System.Text.Json;
var payload = new
{
context = new
{
customerUrn = "sb.00.195",
customerIpAddress = "84.118.92.180",
promotionCode = "CMP1WKWAFY",
interactionType = 10,
channel = 101
}
};
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage(
HttpMethod.Post,
"https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles"
);
request.Headers.Add("x-tn", "e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f");
request.Headers.Add("x-api-key", "sk_dev_acme_sample_123456789");
request.Content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/Json"
);
using var response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
url := "https://acme.sandbox.azotte.com/api/v1/m2m/offer/bundles"
payload := strings.NewReader(`{
"context": {
"customerUrn": "sb.00.195",
"customerIpAddress": "84.118.92.180",
"promotionCode": "CMP1WKWAFY",
"interactionType": 10,
"channel": 101
}
}`)
client := &http.Client{}
req, err := http.NewRequest(http.MethodPost, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Content-Type", "application/Json")
req.Header.Add("x-tn", "e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6f")
req.Header.Add("x-api-key", "sk_dev_acme_sample_123456789")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
Header Breakdown For the Example
Content-Type: application/Jsondeclares the JSON request body exactly as used in your samplex-tn: e2a1c7b2-4f3a-4b8e-9c2d-1a2b3c4d5e6froutes the request into the tenant context you suppliedx-api-key: sk_dev_acme_sample_123456789authenticates the sample Sandbox request with a realistic development key format
Recommended First Setup Sequence
- Create or access your Sandbox project.
- Generate a Sandbox API key.
- Store the key in your backend secrets.
- Make your first API call against
https://acme.sandbox.azotte.com/api/v1/. - Configure webhook or Kafka delivery.
- Validate end-to-end behavior in Sandbox.
- Repeat the configuration in Live when your integration is ready.