Spenza provides various APIs to manage the mobile subscriptions offered in the Spenza marketplace. This document provides the information required to interact with Spenza APIs.
All API endpoints (except the authentication endpoint) require a Bearer token in the Authorization header. You must first obtain this token using the Authentication API.
| Header | Value | Description |
|---|---|---|
| Authorization | Bearer YOUR_TOKEN |
The access token obtained from the Authentication API |
| Content-Type | application/json |
All requests must send and receive JSON data |
Authorization: Bearer eyJhbGciOiJ...
Content-Type: application/json
Note: Replace YOUR_TOKEN with the actual access token received from the Authentication API.
All API calls require authentication using a Bearer Token. You must first obtain this token using the Authenticate API.
GET/api/v1/authenticate
{
"key": "api-key",
"secret": "api-secret"
}
| Field | Type | Description |
|---|---|---|
| key | string | Your API key |
| secret | string | Your API secret |
{
"message": "Authentication Success.",
"accessToken": "Your Auth Token for other APIs.",
"expiration": "token expiration time"
}
/api/v1/sim-by-iccid
{
"ICCID": "9999967890123456789"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
{
"message": "Success.",
"simInfo": {
"status": {
"user": "Assigned",
"device": "Assigned"
},
"operator": {
"custNbr": null
},
"ICCID": "9999967890123456784",
"activationCode": "",
"source": "Other",
"isDeleted": false,
"recommendedPlan": "60af49af21647e2ca0b15f51",
"_id": "632808a8e85110002e3ae629",
"network": "T-Mobile",
"Operator": "T-Mobile",
"phoneNumber": "78993093857",
"group": "63280750e85110002e3ae624",
"account": "63280446e85110002e3ae54e",
"phoneLineStatus": "ACTIVATED"
}
}
/api/v1/plan-by-id
planId: "AT0001"
| Field | Type | Description |
|---|---|---|
| planId | string | Unique identifier for the plan |
/api/v1/purchase-plan
{
"ICCID": "8901260853182965429",
"productId": "product1",
"activateNow": true,
"scheduledDate": "2024-04-20"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
| productId | string | The ID of the plan to purchase |
| activateNow | boolean | Whether to activate the plan immediately |
| scheduledDate | string | Date to schedule activation (YYYY-MM-DD format) |
{
"message": "Success.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_100",
"planCode": "EXPLAN_001",
"status": "ACTIVE",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"cancelledDate": null,
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
/api/v1/activate-subscription
{
"ICCID": "8901260853182965429",
"productId": "product1"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
| productId | string | The ID of the plan to activate |
{
"message": "Success",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_101",
"planCode": "EXPLAN_003",
"status": "ACTIVE",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
/api/v1/cancel-subscription
{
"ICCID": "9999967890123456789"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
{
"message": "Subscription Cancelled.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_100",
"planCode": "EXPLAN_001",
"status": "CANCELLED",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
/api/v1/telco/getUsage
{
"subId": "1745863440782"
}
| Field | Type | Description |
|---|---|---|
| subId | string | The ID of the subscription (found in subId field of subscription object) |
{
"result": {
"usageData": 0,
"usageCalls": 0,
"usageSms": 0,
"usageUpdatedAt": 1747223324287,
"telcoStatus": "ACTIVATED",
"usageDataConverted": {
"format": "B",
"value": 0
},
"network": "Verizon",
"networkCode": "Verizon"
}
}
/api/v1/subscription-by-iccid
{
"ICCID": "9999967890123456789"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
{
"message": "Success.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKAyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "T-Mobile100",
"planCode": "T-Mobile0001",
"status": "Pending",
"initiatedDate": "2022-09-21T04:24:06.473Z",
"startDate": "2022-09-21T04:24:05.000Z",
"endDate": "2022-10-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"cancelledDate": null,
"autoTopUp": true,
"subId": "1663734246473",
"Operator": "T-Mobile",
"network": "T-Mobile",
"sim": "632a916b961e53002e1298d7",
"account": "63280446e85110002e3ae54e",
"orderId": "1339-597673-2114"
}
}
/api/v1/renew-phone-number
Requests a new phone number for the specified SIM card. This endpoint is rate-limited based on your plan configuration.
{
"ICCID": "9999967890123456789"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | The ICCID of the SIM card |
Monthly Rate Limits: This endpoint is subject to monthly rate limits based on your plan configuration. The limit is defined in the plan's apiLimits.renewPhoneNumber property. If no limit is set, all requests are allowed.
IP Tracking: All requests are logged with the originating IP address from the x-forwarded-for header or connection IP. IP addresses are monitored for security and auditing purposes.
{
"message": "Request placed successfully, new number will be assigned soon"
}
/api/v1/public/validate-iccid
Validates the format and checksum of an ICCID. This is a public endpoint and does not require authentication.
{
"ICCID": "8901260853182965429"
}
| Field | Type | Description |
|---|---|---|
| ICCID | string | SIM card ICCID to validate |
{
"isValid": true,
"message": "Valid ICCID."
}
/api/v1/public/validate-imei
Validates the format and Luhn checksum of an IMEI. This is a public endpoint and does not require authentication.
{
"IMEI": "356938035643809"
}
| Field | Type | Description |
|---|---|---|
| IMEI | string | Device IMEI to validate |
{
"isValid": true,
"message": "Valid IMEI."
}
/api/v1/purchase-esim
Initiates asynchronous eSIM purchase and phone number provisioning. The API accepts optional user information. If no user data is provided, the system will use the customer's default employee information.
Requires JWT token in Authorization header: Bearer <token>
{
"imei": "451014850281267",
"simId": "TEST_SPENZA"
}
{
"imei": "451014850281267",
"simId": "SpenzaJ_ESIM",
"user": {
"name": "Testung",
"email": "test+8@spenza.com",
"phoneNumber": "2031134322",
"address": "47 W 13th St",
"city": "New York",
"state": "New York",
"zipcode": "10011"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
| imei | string | Yes | Device IMEI number (exactly 15 digits) |
| simId | string | Yes | SIM Product ID / Product name (e.g., "SpenzaJ_ESIM", "TEST_SPENZA") |
| user | object | No | Optional user/employee information. If not provided, system will use customer's default employee. |
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes* | User's full name |
| string | Yes* | User's email address | |
| zipcode | string | Yes* | 5-digit US ZIP code for location-based number provisioning |
| phoneNumber | string | No | User's phone number |
| address | string | No | User's street address |
| city | string | No | User's city |
| state | string | No | User's state |
* Required only if user object is provided
Important: The system uses the ZIP code to provision phone numbers appropriate for the specified location:
user object is provided with an email that matches an existing employee, that employee's ZIP code is used.user object is provided with a new email, a new employee is created with the provided ZIP code.user object is provided, the system uses the customer's default employee ZIP code.{
"requestId": "64dfa874-f157-431a-a6db-d8e5a915ea12",
"status": "PENDING",
"message": "eSIM purchase initiated successfully"
}
// 400 Bad Request - Missing Required Fields
{
"statusCode": 400,
"message": "imei and simId are required fields",
"error": "Bad Request"
}
// 400 Bad Request - Invalid IMEI
{
"statusCode": 400,
"message": "IMEI must be exactly 15 digits",
"error": "Bad Request"
}
// 400 Bad Request - Invalid IMEI Checksum
{
"statusCode": 400,
"message": "Invalid IMEI number - failed Luhn checksum",
"error": "Bad Request"
}
// 400 Bad Request - Missing User Name
{
"statusCode": 400,
"message": "name should not be empty",
"error": "Bad Request"
}
// 400 Bad Request - Missing User Email
{
"statusCode": 400,
"message": "email should not be empty",
"error": "Bad Request"
}
// 400 Bad Request - Invalid Email Format
{
"statusCode": 400,
"message": "email must be a valid email address",
"error": "Bad Request"
}
// 400 Bad Request - Missing User Zipcode
{
"statusCode": 400,
"message": "zipcode should not be empty",
"error": "Bad Request"
}
// 400 Bad Request - Invalid ZIP Code Format (in user object)
{
"statusCode": 400,
"message": "zipcode must be a valid 5-digit US ZIP code",
"error": "Bad Request"
}
// 400 Bad Request - No ZIP Code Available
{
"statusCode": 400,
"message": "No zipCode available. Please provide user information with zipCode or ensure customer/employee has a zipCode on file.",
"error": "Bad Request"
}
// 400 Bad Request - User Data Mismatch with Existing Employee
{
"statusCode": 400,
"message": "User with email test@example.com already exists. Data mismatch detected: zipcode (provided: 10011, existing: 94102), state (provided: New York, existing: California). Please use the existing employee's information.",
"error": "Bad Request"
}
// 400 Bad Request - Product Not Found
{
"statusCode": 400,
"message": "Product not found",
"error": "Bad Request"
}
// 400 Bad Request - Product Not Available
{
"statusCode": 400,
"message": "Product not available for this customer",
"error": "Bad Request"
}
// 401 Unauthorized - Missing or invalid token
{
"statusCode": 401,
"message": "Authentication required",
"error": "Unauthorized"
}
// 500 Internal Server Error
{
"statusCode": 500,
"message": "eSIM purchase failed",
"error": "Internal Server Error"
}
/api/v1/purchase-esim/:requestId
Retrieves the current status of an eSIM purchase. Poll this endpoint to check when the asynchronous purchase completes.
Requires JWT token in Authorization header: Bearer <token>
| Parameter | Type | Description |
|---|---|---|
| requestId | string | UUID returned from the purchase initiation endpoint |
// Status: PENDING (still processing)
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "PENDING",
"createdAt": "2024-12-05T10:00:00.000Z",
"updatedAt": "2024-12-05T10:00:00.000Z"
}
// Status: PROCESSING (in progress)
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "PROCESSING",
"createdAt": "2024-12-05T10:00:00.000Z",
"updatedAt": "2024-12-05T10:00:15.000Z"
}
// Status: SUCCESS (completed)
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "SUCCESS",
"result": {
"mdn": "1234567890",
"iccid": "89012345678901234567",
"qrCode": "https://s3.amazonaws.com/esim-activation-code/customer-id/iccid-esim-activation-qrcode.png"
},
"createdAt": "2024-12-05T10:00:00.000Z",
"updatedAt": "2024-12-05T10:00:45.000Z"
}
// Status: FAILED (error occurred)
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "FAILED",
"failureReason": "Insufficient inventory",
"createdAt": "2024-12-05T10:00:00.000Z",
"updatedAt": "2024-12-05T10:00:30.000Z"
}
// 404 Not Found - Request doesn't exist or unauthorized
{
"statusCode": 404,
"message": "Purchase request not found",
"error": "Not Found"
}
// 401 Unauthorized
{
"statusCode": 401,
"message": "Authentication required",
"error": "Unauthorized"
}
/api/v1/webhooks/register
Registers webhook callback URLs for a specific operator and CDP. The eventType is provided in the
request body and controls which URL fields are required. Delivery authentication is configured via the
authentication object (e.g., HTTP Basic).
{
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user",
"password": "super-secret"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks"
}
| Field | Type | Description |
|---|---|---|
| operator | string | Operator identifier. |
| cdpType | string | Operator CDP type (e.g. SpenzaJ, SpenzaG). Must match the CDP type configured in the system. |
| eventType | string | sms, voice, or both. Determines which URL fields are required. |
| authentication.type | string | Delivery auth type (e.g. basic, none). |
| authentication.username | string | Username used when authentication.type = basic. |
| authentication.password | string | Password used when authentication.type = basic. |
| webhookUrls.messageUrl* | string (URL) | Inbound SMS webhook. Required for sms or both. |
| webhookUrls.callbackMessageUrl* | string (URL) | DLR webhook for SMS. Required for sms or both. |
| webhookUrls.voiceUrl* | string (URL) | Inbound voice webhook. Required for voice or both. |
| webhookUrls.callbackVoiceUrl* | string (URL) | Voice delivery status webhook. Required for voice or both. |
| retryPolicy.maxAttempts | number | Maximum retry attempts (default 5). |
| retryPolicy.backoffStrategy | string | Backoff strategy (e.g., fixed, exponential). |
| retryPolicy.initialDelaySeconds | number | Initial delay before first retry, in seconds. |
| retryPolicy.maxDelaySeconds | number | Maximum delay between retries, in seconds. |
| status | string | Registration status, e.g. active or inactive. |
| description | string | Human-readable description. |
Fields marked with * are conditionally required based on eventType (sms, voice, or both).
{
"message": "Webhook registered",
"registration": {
"_id": "69146d70ed68e3890a45c228",
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks",
"createdAt": "2025-01-10T09:15:01.000Z",
"updatedAt": "2025-01-10T09:15:01.000Z"
}
}
Response objects always include both SMS and voice URL fields; unused fields are returned as null. Save the _id field to use when deleting this registration.
/api/v1/webhooks/registrations
Retrieve registered webhook callbacks for the authenticated account. Use optional query parameters to filter results.
| Parameter | Type | Description |
|---|---|---|
| eventType | string | Filter by sms, voice, or both |
| operator | string | Filter by operator CDP type (e.g., SpenzaJ) |
{
"registrations": [
{
"_id": "69146d70ed68e3890a45c228",
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks",
"createdAt": "2025-01-10T09:15:01.000Z",
"updatedAt": "2025-01-10T09:15:01.000Z"
}
]
}
Each entry includes both SMS and voice URL fields. Unused fields are returned as null.
/api/v1/webhooks/registrations/:id
Delete a webhook registration by its registration ID.
| Parameter | Type | Description |
|---|---|---|
| id | string (MongoId) | The registration ID (obtained from List Webhooks endpoint) |
{
"message": "Webhook registration deleted successfully"
}
# Registration Not Found
{
"error": "Webhook registration not found"
}
# Unauthorized
{
"error": "Unauthorized"
}
/api/v1/customer/register-sip
Register or update your SIP configuration.
{
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
}
| Field | Type | Description |
|---|---|---|
| sipIngressIp | string | Your SIP ingress IP address |
{
"message": "SIP configuration registered successfully",
"sipConfig": {
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
},
"isSIPEnabled": true
}
/api/v1/customer/register-sip
Retrieve your current SIP configuration.
{
"isSIPEnabled": true,
"sipConfig": {
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
}
}
/api/v1/customer/register-sip
Delete your SIP configuration and disable SIP.
{
"message": "SIP configuration deleted successfully"
}
The V3 API endpoints use an asynchronous pattern for long-running operations. Instead of waiting for the operation to complete, these endpoints return immediately with a transactionId that you can use to poll for status updates.
Step 1: Call any V3 endpoint (e.g., /api/v3/purchase-plan)
Step 2: Receive immediate response with transactionId and statusEndpoint
Step 3: Poll the status endpoint regularly (recommended: every 5 seconds)
Step 4: When status is COMPLETED, retrieve the final result
| Status | Description |
|---|---|
PENDING |
Transaction created, waiting to be processed |
PROCESSING |
Operation is currently being executed |
COMPLETED |
Operation finished successfully, result available |
FAILED |
Operation failed, error message available |
/api/v3/transaction/:transactionId/status
Retrieves the current status of an async transaction. This endpoint is public and does not require authentication - the transaction ID acts as the authorization token.
| Parameter | Type | Description |
|---|---|---|
| transactionId | string | The transaction ID returned from the async API call |
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "PENDING",
"message": "Transaction is pending",
"timestamp": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "COMPLETED",
"message": "Transaction completed successfully",
"timestamp": "2024-01-15T10:32:00.000Z",
"result": {
"subscription": {
"subscriptionId": "sub_12345",
"status": "ACTIVE",
"planName": "Premium Plan"
}
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:32:00.000Z",
"processingStartedAt": "2024-01-15T10:30:01.000Z",
"processingCompletedAt": "2024-01-15T10:32:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "FAILED",
"message": "Transaction failed",
"timestamp": "2024-01-15T10:31:00.000Z",
"error": "Insufficient balance",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:31:00.000Z"
}
Performance: Status checks hit Redis cache first (~1-2ms), falling back to MongoDB only if needed (~20-50ms). Cache has 24-hour TTL.
/api/v3/purchase-plan
Initiates an asynchronous plan purchase. Returns immediately with a transaction ID for status polling.
{
"iccid": "8901260853182965429",
"productName": "Premium_Plan_100GB",
"activateNow": true,
"scheduleDate": "2024-04-20"
}
| Field | Type | Description |
|---|---|---|
| iccid | string | The ICCID of the SIM card |
| productName | string | The name/ID of the plan to purchase |
| activateNow | boolean | Optional. Defaults to true if scheduleDate omitted, false if scheduleDate provided |
| scheduleDate | string | Optional. Date to schedule activation (YYYY-MM-DD format) |
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"statusEndpoint": "/api/v3/transaction/v3_1698765432100_abc123/status",
"message": "Transaction initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Timeout: 15 minutes. If the operation doesn't complete within this time, it will be marked as FAILED.
/api/v3/activate-subscription
Activates a previously purchased subscription asynchronously.
{
"iccid": "8901260853182965429",
"productId": "product_12345"
}
| Field | Type | Description |
|---|---|---|
| iccid | string | The ICCID of the SIM card |
| productId | string | The ID of the plan to activate |
{
"success": true,
"transactionId": "v3_1698765432101_def456",
"statusEndpoint": "/api/v3/transaction/v3_1698765432101_def456/status",
"message": "Activation initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Timeout: 15 minutes
/api/v3/cancel-subscription
Cancels an active subscription asynchronously.
{
"iccid": "8901260853182965429"
}
| Field | Type | Description |
|---|---|---|
| iccid | string | The ICCID of the SIM card with the subscription to cancel |
{
"success": true,
"transactionId": "v3_1698765432102_ghi789",
"statusEndpoint": "/api/v3/transaction/v3_1698765432102_ghi789/status",
"message": "Cancellation initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Timeout: 15 minutes
/api/v3/esim-purchase
Purchases and provisions an eSIM asynchronously. This operation can take up to 45 minutes.
{
"deviceId": "device_12345",
"planId": "plan_67890",
"imei": "356938035643809",
"activateNow": true
}
| Field | Type | Description |
|---|---|---|
| deviceId | string | The device identifier |
| planId | string | The ID of the plan to purchase |
| imei | string | Device IMEI number (15 digits) |
| activateNow | boolean | Whether to activate immediately |
{
"success": true,
"transactionId": "v3_1698765432103_jkl012",
"statusEndpoint": "/api/v3/transaction/v3_1698765432103_jkl012/status",
"message": "eSIM purchase initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Timeout: 60 minutes. eSIM provisioning can take up to 45 minutes, so this operation has an extended timeout.
/api/v3/renew-phone-number
Requests a new phone number for a SIM card asynchronously. Subject to rate limits based on your plan.
{
"iccid": "8901260853182965429"
}
| Field | Type | Description |
|---|---|---|
| iccid | string | The ICCID of the SIM card |
{
"success": true,
"transactionId": "v3_1698765432104_mno345",
"statusEndpoint": "/api/v3/transaction/v3_1698765432104_mno345/status",
"message": "Phone number renewal initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
Monthly Rate Limits: This endpoint is subject to monthly rate limits based on your plan configuration. The limit is defined in the plan's apiLimits.renewPhoneNumber property.
Timeout: 15 minutes
| HTTP Code | Message | Description |
|---|---|---|
| 400 | Missing Fields | Required fields are missing in the request |
| 400 | Invalid API Credentials | The provided API credentials are invalid |
| 400 | Plan Not Found | The requested plan does not exist |
| 400 | Sim Not Found | The requested SIM does not exist |
| 400 | Subscription Not Found | The requested subscription does not exist |
| 429 | Rate Limit Exceeded | Monthly rate limit exceeded for API requests |
| 401 | Unauthorized | Invalid or missing authentication token |
| 403 | Forbidden | Access denied or insufficient permissions |
| 500 | Internal Server Error | Something went wrong at our end |
https://api-prod.spenza.com
# All authenticated endpoints require these headers
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
# Step 1: Get your API credentials from Spenza
# Step 2: Call /api/v1/authenticate to get access token
# Step 3: Use the token in all subsequent API calls
# Example: Authenticate first
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/authenticate' \
-H 'Content-Type: application/json' \
-d '{
"key": "your-api-key",
"secret": "your-api-secret"
}'
{
"message": "Authentication Success.",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiration": "2024-01-16T10:30:00.000Z"
}
# Include the token in Authorization header
$ curl \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'Content-Type: application/json' \
'https://api-prod.spenza.com/api/v1/sim-by-iccid'
# Get your authentication token
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/authenticate' \
-H 'Content-Type: application/json' \
-d '{
"key": "api-key",
"secret": "api-secret"
}'
{
"message": "Authentication Success.",
"accessToken": "Your Auth Token for other APIs.",
"expiration": "token expiration time"
}
# Use the received token in subsequent API calls
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/sim-by-iccid' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "9999967890123456789"
}'
# Missing Fields
{
"errors": [{
"message": "Api Key and Secrets are Required Fields.",
"fields": ["key", "secret"]
}]
}
# Missing field key
{
"errors": [{
"message": "Api Key is Required Field.",
"fields": ["key"]
}]
}
# Missing field secret
{
"errors": [{
"message": "Api Secret is Required Field.",
"fields": ["secret"]
}]
}
# Invalid API Credentials
{
"errors": [{
"message": "Invalid Api Credentials."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Retrieve SIM information using ICCID
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/sim-by-iccid' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "9999967890123456789"
}'
{
"message": "Success.",
"simInfo": {
"status": {
"user": "Assigned",
"device": "Assigned"
},
"operator": {
"custNbr": null
},
"ICCID": "9999967890123456784",
"activationCode": "",
"source": "Other",
"isDeleted": false,
"recommendedPlan": "60af49af21647e2ca0b15f51",
"_id": "632808a8e85110002e3ae629",
"network": "T-Mobile",
"Operator": "T-Mobile",
"phoneNumber": "78993093857",
"group": "63280750e85110002e3ae624",
"account": "63280446e85110002e3ae54e",
"phoneLineStatus": "ACTIVATED"
}
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID is required field.",
"field": "ICCID"
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Retrieve plan information using planId
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/plan-by-id' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"planId": "AT0001"
}'
{
"message": "Success.",
"plan": {
"stripe": {
"price": "price_1LgUXYAq7JKAyJICWrRooGBI"
},
"productName": "AT&T100",
"category": "PLANS",
"Operator": "AT&T",
"network": "AT&T",
"zone": "US",
"validityDays": 30,
"dataMB": 10,
"speed": "4G",
"price": 10,
"inStock": 0,
"durationType": "Monthly",
"isDeleted": false,
"_id": "63184df1203d4994052869f7",
"description": "AT&T Plan 1",
"productId": "AT0001",
"feature": []
}
}
# Missing field planId
{
"errors": [{
"message": "Plan Id is Required.",
"field": "planId"
}]
}
# Plan Not Found
{
"errors": [{
"message": "Plan Not Found."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Purchase a plan using ICCID, productId and schedule info
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/purchase-plan' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "8901260853182965429",
"productId": "product1",
"activateNow": true,
"scheduledDate": "2024-04-20"
}'
{
"message": "Success.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_100",
"planCode": "EXPLAN_001",
"status": "ACTIVE",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"cancelledDate": null,
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID Key is Required Field.",
"fields": ["ICCID"]
}]
}
# Missing field productId
{
"errors": [{
"message": "productId is Required Field.",
"fields": ["productId"]
}]
}
# Missing field activateNow
{
"errors": [{
"message": "activateNow is Required Field.",
"fields": ["activateNow"]
}]
}
# Missing field scheduledDate
{
"errors": [{
"message": "scheduledDate is Required Field. Format:(YYYY-MM-DD)",
"fields": ["scheduledDate"]
}]
}
# Plan Not Found
{
"errors": [{
"message": "Plan Not Found."
}]
}
# Operator Mismatch
{
"errors": [{
"message": "Sim Is Not Compatible. Please check Plan Operator and Sim Operator."
}]
}
# Active Subscription Exists
{
"errors": [{
"message": "Sim Already has an Active Subscription."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something Went Wrong at our End. Our Engineers are being Notified about this Error."
}]
}
# Activate a purchased plan
$ curl \
-X PUT 'https://api-prod.spenza.com/api/v1/activate-subscription' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "8901260853182965429",
"productId": "product1"
}'
{
"message": "Success",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_101",
"planCode": "EXPLAN_003",
"status": "ACTIVE",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID is Required Field.",
"fields": ["ICCID"]
}]
}
# Missing field productId
{
"errors": [{
"message": "productId is Required Field.",
"fields": ["productId"]
}]
}
# Plan Not Found
{
"errors": [{
"message": "Plan Not Found."
}]
}
# Sim Not Found
{
"errors": [{
"message": "Sim Not Found."
}]
}
# Subscription Not Found
{
"errors": [{
"message": "Subscription Not Found."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Cancel an active subscription
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/cancel-subscription' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "9999967890123456789"
}'
{
"message": "Subscription Cancelled.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKDyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "EXPLAN_100",
"planCode": "EXPLAN_001",
"status": "CANCELLED",
"initiatedDate": "2022-08-21T04:24:06.473Z",
"startDate": "2022-08-21T04:24:05.000Z",
"endDate": "2022-11-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"autoTopUp": true,
"subId": "1663734246474",
"Operator": "T-Mobile",
"network": "T-Mobile",
"orderId": "1739-597673-2114"
}
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID is required field.",
"fields": ["ICCID"]
}]
}
# Sim Not Found
{
"errors": [{
"message": "Sim Not Found."
}]
}
# Subscription Not Found
{
"errors": [{
"message": "Subscription Not Found."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Retrieve subscription by ICCID
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/subscription-by-iccid' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "9999967890123456789"
}'
{
"message": "Success.",
"subscription": {
"stripe": {
"subId": "sub_1LkKThAq7JKAyJICNJ3l1WWv",
"scheduleId": null,
"price": null
},
"operatorRes": {
"MDN": null,
"description": null
},
"planName": "T-Mobile100",
"planCode": "T-Mobile0001",
"status": "Pending",
"initiatedDate": "2022-09-21T04:24:06.473Z",
"startDate": "2022-09-21T04:24:05.000Z",
"endDate": "2022-10-21T04:24:05.000Z",
"scheduledDate": "2022-09-20T00:00:00.000Z",
"cancelledDate": null,
"autoTopUp": true,
"subId": "1663734246473",
"Operator": "T-Mobile",
"network": "T-Mobile",
"sim": "632a916b961e53002e1298d7",
"account": "63280446e85110002e3ae54e",
"orderId": "1339-597673-2114"
}
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID is required field.",
"field": "ICCID"
}]
}
# Sim Not Found
{
"errors": [{
"message": "Sim Not Found."
}]
}
# Subscription Not Found
{
"errors": [{
"message": "Subscription Not Found."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something Went Wrong at our End. Our Engineers are being Notified about this Error."
}]
}
# Retrieve the usage of a Sim
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/telco/getUsage' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"subId": "1745863440782"
}'
{
"result": {
"usageData": 0,
"usageCalls": 0,
"usageSms": 0,
"usageUpdatedAt": 1747223324287,
"telcoStatus": "ACTIVATED",
"usageDataConverted": {
"format": "B",
"value": 0
},
"network": "Verizon",
"networkCode": "Verizon"
}
}
# Missing field subId
{
"errors": [{
"message": "Subscription Id is a Required Field.",
"fields": ["subId"]
}]
}
# No Active Invoice
{
"errors": [{
"message": "Subscription Don't have any Active Invoices."
}]
}
# Internal Server Error
{
"errors": [{
"message": "Something is Wrong at our end. Our Engineers are being Notified."
}]
}
# Request a new phone number for a SIM card
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/renew-phone-number' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "9999967890123456789"
}'
{
"message": "Request placed successfully, new number will be assigned soon"
}
# Missing field ICCID
{
"errors": [{
"message": "ICCID is required field.",
"fields": ["ICCID"]
}]
}
# Subscription Not Found
{
"errors": [{
"message": "Subscription Not Found. Please Create an Active Subscription First."
}]
}
# Rate Limit Exceeded
{
"errors": [{
"message": "Monthly rate limit exceeded for renew phone number requests."
}]
}
# Internal Server Error
{
"error": "Something went wrong"
}
# Validate ICCID format (no auth required)
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/public/validate-iccid' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "8901260853182965429"
}'
{
"isValid": true,
"message": "Valid ICCID."
}
# Validate IMEI format (no auth required)
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/public/validate-imei' \
-H 'Content-Type: application/json' \
-d '{
"IMEI": "356938035643809"
}'
{
"isValid": true,
"message": "Valid IMEI."
}
# Purchase eSIM with IMEI and SIM ID only
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/purchase-esim' \
-H 'Authorization: Bearer YOUR_JWT_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"imei": "451014850281267",
"simId": "TEST_SPENZA"
}'
# Purchase eSIM with user information for number provisioning
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/purchase-esim' \
-H 'Authorization: Bearer YOUR_JWT_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"imei": "451014850281267",
"simId": "SpenzaJ_ESIM",
"user": {
"name": "Testung",
"email": "test+8@spenza.com",
"phoneNumber": "2031134322",
"address": "47 W 13th St",
"city": "New York",
"state": "New York",
"zipcode": "10011"
}
}'
{
"requestId": "64dfa874-f157-431a-a6db-d8e5a915ea12",
"status": "PENDING",
"message": "eSIM purchase initiated successfully"
}
# After successful eSIM purchase:
# 1. Subscription is created with PENDING status
# 2. Phone number is provisioned based on the user's ZIP code location
# 3. eSIM QR code is generated and sent to customer via email
# 4. Customer can activate eSIM by scanning the QR code
# Poll for purchase status
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/purchase-esim/550e8400-e29b-41d4-a716-446655440000' \
-H 'Authorization: Bearer YOUR_JWT_TOKEN'
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"status": "SUCCESS",
"result": {
"mdn": "1234567890",
"iccid": "89012345678901234567",
"qrCode": "https://s3.amazonaws.com/esim-activation-code/customer-id/iccid-esim-activation-qrcode.png"
},
"createdAt": "2024-12-05T10:00:00.000Z",
"updatedAt": "2024-12-05T10:00:45.000Z"
}
# Register webhook for SMS and Voice events
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/webhooks/register' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user",
"password": "super-secret"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks for production"
}'
{
"message": "Webhook registered",
"registration": {
"_id": "69146d70ed68e3890a45c228",
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks for production",
"createdAt": "2025-01-10T09:15:01.000Z",
"updatedAt": "2025-01-10T09:15:01.000Z"
}
}
Response objects always include both SMS and voice URL fields; unused fields are returned as null. Save the _id field to delete this registration later.
# List registered webhooks
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/webhooks/registrations?eventType=both' \
-H 'Authorization: Bearer YOUR_TOKEN'
{
"registrations": [
{
"_id": "69146d70ed68e3890a45c228",
"operator": "SpenzaJ",
"cdpType": "SpenzaJ",
"eventType": "both",
"authentication": {
"type": "basic",
"username": "webhook-user"
},
"webhookUrls": {
"messageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackMessageUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"voiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af",
"callbackVoiceUrl": "https://webhook.site/dcc5393e-cb1e-4005-9e80-1c80b7a011af"
},
"retryPolicy": {
"maxAttempts": 5,
"backoffStrategy": "fixed",
"initialDelaySeconds": 2,
"maxDelaySeconds": 300
},
"status": "active",
"description": "Combined SMS and Voice webhooks",
"createdAt": "2025-01-10T09:15:01.000Z",
"updatedAt": "2025-01-10T09:15:01.000Z"
}
]
}
Each entry includes both SMS and voice URL fields. Unused fields are returned as null.
# Delete webhook registration by ID
$ curl \
-X DELETE 'https://api-prod.spenza.com/api/v1/webhooks/registrations/69146d70ed68e3890a45c228' \
-H 'Authorization: Bearer YOUR_TOKEN'
{
"message": "Webhook registration deleted successfully"
}
# Registration Not Found
{
"error": "Webhook registration not found"
}
# Unauthorized
{
"error": "Unauthorized"
}
# Register or update SIP configuration
$ curl \
-X POST 'https://api-prod.spenza.com/api/v1/customer/register-sip' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
}'
{
"message": "SIP configuration registered successfully",
"sipConfig": {
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
},
"isSIPEnabled": true
}
# Retrieve your SIP configuration
$ curl \
-X GET 'https://api-prod.spenza.com/api/v1/customer/register-sip' \
-H 'Authorization: Bearer YOUR_TOKEN'
{
"isSIPEnabled": true,
"sipConfig": {
"sipIngressIp": "203.0.113.10",
"sipPort": 5060,
"transport": "udp",
"codecs": ["ulaw", "alaw"],
"didRanges": ["+1415000xxxx", "+1818444xxxx"],
"allowedSourceIps": ["203.0.113.10", "203.0.113.11"]
}
}
# Delete SIP configuration and disable SIP
$ curl \
-X DELETE 'https://api-prod.spenza.com/api/v1/customer/register-sip' \
-H 'Authorization: Bearer YOUR_TOKEN'
{
"message": "SIP configuration deleted successfully"
}
# Step 1: Initiate async operation
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/purchase-plan' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429",
"productName": "Premium_Plan",
"activateNow": true
}'
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"statusEndpoint": "/api/v3/transaction/v3_1698765432100_abc123/status",
"message": "Transaction initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
$ curl \
'https://api-prod.spenza.com/api/v3/transaction/v3_1698765432100_abc123/status'
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "COMPLETED",
"result": {
"subscription": {
"subscriptionId": "sub_12345",
"status": "ACTIVE"
}
},
"timestamp": "2024-01-15T10:32:00.000Z"
}
# Check transaction status (no auth required)
$ curl \
'https://api-prod.spenza.com/api/v3/transaction/v3_1698765432100_abc123/status'
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "PENDING",
"message": "Transaction is pending",
"timestamp": "2024-01-15T10:30:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "COMPLETED",
"result": {
"subscription": {
"subscriptionId": "sub_12345",
"status": "ACTIVE"
}
},
"processingStartedAt": "2024-01-15T10:30:01.000Z",
"processingCompletedAt": "2024-01-15T10:32:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"status": "FAILED",
"error": "Insufficient balance",
"timestamp": "2024-01-15T10:31:00.000Z"
}
# Initiate async plan purchase
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/purchase-plan' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429",
"productName": "Premium_Plan_100GB",
"activateNow": true
}'
{
"success": true,
"transactionId": "v3_1698765432100_abc123",
"statusEndpoint": "/api/v3/transaction/v3_1698765432100_abc123/status",
"message": "Transaction initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/purchase-plan' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429",
"productName": "Premium_Plan",
"scheduleDate": "2024-04-20"
}'
# Activate subscription asynchronously
$ curl \
-X PUT 'https://api-prod.spenza.com/api/v3/activate-subscription' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429",
"productId": "product_12345"
}'
{
"success": true,
"transactionId": "v3_1698765432101_def456",
"statusEndpoint": "/api/v3/transaction/v3_1698765432101_def456/status",
"message": "Activation initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
# Cancel subscription asynchronously
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/cancel-subscription' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429"
}'
{
"success": true,
"transactionId": "v3_1698765432102_ghi789",
"statusEndpoint": "/api/v3/transaction/v3_1698765432102_ghi789/status",
"message": "Cancellation initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
# Initiate eSIM purchase (can take up to 45 minutes)
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/esim-purchase' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"deviceId": "device_12345",
"planId": "plan_67890",
"imei": "356938035643809",
"activateNow": true
}'
{
"success": true,
"transactionId": "v3_1698765432103_jkl012",
"statusEndpoint": "/api/v3/transaction/v3_1698765432103_jkl012/status",
"message": "eSIM purchase initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432103_jkl012",
"status": "COMPLETED",
"result": {
"mdn": "1234567890",
"iccid": "89012345678901234567",
"qrCode": "https://s3.amazonaws.com/esim-qr-codes/abc123.png"
}
}
# Request new phone number asynchronously
$ curl \
-X POST 'https://api-prod.spenza.com/api/v3/renew-phone-number' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"iccid": "8901260853182965429"
}'
{
"success": true,
"transactionId": "v3_1698765432104_mno345",
"statusEndpoint": "/api/v3/transaction/v3_1698765432104_mno345/status",
"message": "Phone number renewal initiated",
"timestamp": "2024-01-15T10:30:00.000Z"
}
{
"success": true,
"transactionId": "v3_1698765432104_mno345",
"status": "COMPLETED",
"result": {
"newPhoneNumber": "+15551234567",
"iccid": "8901260853182965429"
}
}
{
"errors": [{
"message": "Missing required field: ICCID",
"fields": ["ICCID"]
}]
}
{
"statusCode": 401,
"message": "Invalid or expired authentication token",
"error": "Unauthorized"
}
{
"statusCode": 403,
"message": "Access denied. Insufficient permissions.",
"error": "Forbidden"
}
{
"statusCode": 404,
"message": "Resource not found",
"error": "Not Found"
}
{
"statusCode": 429,
"message": "Monthly rate limit exceeded for this operation",
"error": "Too Many Requests",
"retryAfter": "2024-02-01T00:00:00.000Z"
}
{
"statusCode": 500,
"message": "Something went wrong at our end. Our engineers are being notified.",
"error": "Internal Server Error"
}
# Always check the HTTP status code
$ curl \
-w '\nHTTP Status: %{http_code}\n' \
-X GET 'https://api-prod.spenza.com/api/v1/sim-by-iccid' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"ICCID": "8901260853182965429"
}'