Plans API
Plans API is designed to manage subscription plans efficiently. It supports plan creation, listing all plans, retrieval by ID, modification, and deletion, allowing seamless management of memberships.
The API ensures clear and consistent responses, including detailed error handling, to provide a smooth experience for developers.
Create a plan¶
Endpoint
POST /v1/plans/
This endpoint allows creating a new recurring plan in the system by sending a POST request with the plan details — such as name, description, amount, currency, interval (frequency of charge), trial_period_days, and an optional image. If the operation is successful, it confirms the plan’s creation and provides its unique key.
Query Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| test | Indicates if the plan is in test mode | boolean | false |
Request Body Fields:
| Parameter | Description | Type | Required |
|---|---|---|---|
| name | Plan name (max 50 characters) | string | true |
| description | Plan description (max 300 characters) | string | false |
| currency | Currency code (USD, EUR, CRC, etc.) | string | true |
| amount | Plan price (decimal format) | decimal | true |
| interval | Billing frequency (month, year) | string | true |
| interval_count | Number of intervals between billings | integer | true |
| trial_period_days | Trial period in days | integer | false |
| image | Base64 encoded image or image URL | string | false |
Request (cURL):
curl -X POST 'http://127.0.0.1:8000/v1/plans/?test=false' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123' \
-H 'Content-Type: application/json' \
-d '{
"name": "Premium Plan",
"description": "Unlimited access to all features",
"currency": "USD",
"amount": 9.99,
"interval": "month",
"interval_count": 1,
"trial_period_days": 7,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
}'
Request (Python):
import requests
api_key = "sk_test_51O62xYzAbcDef123"
response = requests.post(
'http://127.0.0.1:8000/v1/plans/?test=false',
headers={
'Authorization': f'Api-Key {api_key}',
'Content-Type': 'application/json'
},
json={
"name": "Premium Plan",
"description": "Unlimited access to all features",
"currency": "USD",
"amount": 9.99,
"interval": "month",
"interval_count": 1,
"trial_period_days": 7
}
)
print(response.json())
Request (Postman):
- Method: POST
- URL:
http://127.0.0.1:8000/v1/plans/?test=false - Authorization: Api-Key with value
sk_test_51O62xYzAbcDef123 - Body (raw JSON):
{
"name": "Premium Plan",
"description": "Unlimited access to all features",
"currency": "USD",
"amount": 9.99,
"interval": "month",
"interval_count": 1,
"trial_period_days": 7
}
Response (201 Created):
{
"code": 201,
"title": "Complete registration",
"content": "The registration was successfully completed.",
"type": "success",
"data": {
"id": "d36a4a5c-9fa9-4d55-b47f-4f1d50f2a180"
}
}
Get all plans¶
Endpoint
GET /v1/plans/
This endpoint retrieves a paginated list of all plans with advanced filtering support.
Query Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| page | Page number for pagination (default: 1) | integer | false |
| page_size | Number of plans per page (default: 10, max: 100) | integer | false |
| test | Filter by test mode (true/false) | boolean | false |
| name | Search by plan name | string | false |
| price_min | Minimum plan price | decimal | false |
| price_max | Maximum plan price | decimal | false |
| interval | Filter by billing interval (month, year) | string | false |
| interval_count | Filter by interval count | integer | false |
| subscribers_min | Minimum number of active subscribers | integer | false |
| subscribers_max | Maximum number of active subscribers | integer | false |
| trial_days | Filter by trial period days | integer | false |
| status | Filter by status (active/inactive, true/false) | string | false |
Request (List All Plans):
curl -X GET 'http://127.0.0.1:8000/v1/plans/?page=1&page_size=10&test=false' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123'
Request (With Filters):
curl -X GET 'http://127.0.0.1:8000/v1/plans/?page=1&name=premium&price_min=5&price_max=50&status=active' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123'
Response (200 OK):
{
"count": 2,
"current_page": 1,
"total_pages": 1,
"results": [
{
"key": "f1a2b3c4-5678-90ab-cdef-1234567890ab",
"information": {
"name": "Premium Plan",
"created": "2025-08-17T20:00:00Z",
"interval": "month",
"interval_count": 1,
"currency": "USD",
"amount": "9.99",
"trial_period_days": 7,
"credit_card_description": "PREMIUM",
"description": "Unlimited access to all features with premium support.",
"email": "developer@example.com",
"company_name": "Acme Corp",
"page": "https://acme.com",
"active": true,
"count": 150,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
"image_dev": "https://acme.com/logo.png"
},
"test": false
},
{
"key": "a1b2c3d4-5678-90ef-ghij-1234567890cd",
"information": {
"name": "Basic Plan",
"created": "2025-08-17T20:05:00Z",
"interval": "month",
"interval_count": 1,
"currency": "USD",
"amount": "4.99",
"trial_period_days": 0,
"credit_card_description": "BASIC",
"description": "Limited access to basic features with standard support.",
"email": "developer@example.com",
"company_name": "Acme Corp",
"page": "https://acme.com",
"active": true,
"count": 45,
"image": null,
"image_dev": "https://acme.com/logo.png"
},
"test": false
}
]
}
Get a specific plan¶
Endpoint
GET /v1/plans/{id}/
This endpoint retrieves complete details of a specific plan by its unique key.
Path Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| id | The unique identifier of a plan (key) | string | true |
Query Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| test | Filter by test mode (true/false) | boolean | false |
Request:
curl -X GET 'http://127.0.0.1:8000/v1/plans/f9b77185-a62e-4da9-a056-3c7b812ca334/' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123'
Response (200 OK):
{
"key": "f9b77185-a62e-4da9-a056-3c7b812ca334",
"information": {
"name": "Standard Plan",
"created": "2025-03-25T08:50:15.732299Z",
"interval": "month",
"interval_count": 1,
"currency": "USD",
"amount": "19.99",
"trial_period_days": 0,
"credit_card_description": "STANDARD",
"description": "This plan offers access to standard features with basic support.",
"email": "developer@example.com",
"company_name": "Acme Corp",
"page": "https://acme.com",
"active": true,
"count": 75,
"image": null,
"image_dev": "https://acme.com/logo.png"
},
"test": true
}
Response (404 Not Found):
{
"code": 404,
"title": "Plan does not exist",
"content": "The requested plan does not exist, please verify.",
"type": "danger"
}
Update a plan¶
Endpoint
PUT /v1/plans/{id}/
Updates an existing plan with new details. You can update individual fields including name, description, image, and trial period days without affecting others.
Path Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| id | The unique identifier of a plan (key) | string | true |
Query Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| test | Filter by test mode (true/false) | boolean | false |
Request Body Fields (all optional):
| Parameter | Description | Type |
|---|---|---|
| name | Plan name (max 50 characters) | string |
| description | Plan description (max 300 characters) | string |
| image | Base64 encoded image or image URL | string |
| trial_period_days | Trial period in days | integer |
| is_test | Indicates test or production environment | boolean |
Request:
curl -X PUT 'http://127.0.0.1:8000/v1/plans/f9b77185-a62e-4da9-a056-3c7b812ca334/' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123' \
-H 'Content-Type: application/json' \
-d '{
"name": "Updated Premium Plan",
"description": "Updated description with full access to features",
"trial_period_days": 14,
"is_test": false
}'
Response (200 OK):
{
"code": 200,
"title": "Plan actualizado",
"content": "El plan Updated Premium Plan fue actualizado correctamente.",
"type": "success",
"data": "f9b77185-a62e-4da9-a056-3c7b812ca334"
}
Response (404 Not Found):
{
"code": 404,
"title": "Plan no encontrado",
"content": "El plan con ID f9b77185-a62e-4da9-a056-3c7b812ca334 no existe o no tienes permisos para modificarlo.",
"type": "danger"
}
Response (200 - No Changes):
{
"code": 200,
"title": "Sin cambios",
"content": "No se detectaron cambios en el plan.",
"type": "info",
"data": "f9b77185-a62e-4da9-a056-3c7b812ca334"
}
Delete a plan¶
Endpoint
DELETE /v1/plans/{id}/
Permanently deletes a plan and all associated subscriptions. When a plan is deleted, all customers with active subscriptions are notified via email.
Path Parameters:
| Parameter | Description | Type | Required |
|---|---|---|---|
| id | The unique identifier of a plan (key) | string | true |
Request:
curl -X DELETE 'http://127.0.0.1:8000/v1/plans/f9b77185-a62e-4da9-a056-3c7b812ca334/' \
-H 'Authorization: Api-Key sk_test_51O62xYzAbcDef123'
Response (200 OK):
{
"code": 200,
"title": "Plan deleted",
"content": "The plan f9b77185-a62e-4da9-a056-3c7b812ca334 was deleted successfully.",
"type": "success"
}
Response (404 Not Found):
{
"code": 404,
"title": "Plan does not exist",
"content": "The plan f9b77185-a62e-4da9-a056-3c7b812ca334 does not exist or has already been deleted.",
"type": "danger"
}
Error Handling¶
The API returns standard HTTP status codes to indicate the success or failure of a request. Below are common errors specific to plans:
400 Bad Request¶
Occurs when the request is malformed or has invalid data.
Scenarios:
| Scenario | Error Message | Solution |
|---|---|---|
| Invalid price range | "El precio mínimo no puede ser mayor que el máximo." | Ensure price_min ≤ price_max |
| Invalid subscriber range | "El mínimo de suscriptores no puede ser mayor que el máximo." | Ensure subscribers_min ≤ subscribers_max |
| Plan not found | "El plan consultado no existe." | Verify the plan key or filters |
Example Error Response:
{
"code": 400,
"title": "Rango de precios inválido",
"content": "El precio mínimo no puede ser mayor que el máximo.",
"type": "warning"
}
401 Unauthorized¶
Authentication failed. API Key is invalid, missing, or malformed.
Example:
Solution:
- Verify you included the
Authorization: Api-Key sk_test_...header - Ensure your API Key is correct and active
- Test with Postman using the Api-Key authentication method
404 Not Found¶
The requested plan does not exist.
Example:
{
"code": 404,
"title": "Plan does not exist",
"content": "The requested plan does not exist, please verify.",
"type": "danger"
}
Solution:
- Verify the plan key exists
- Use the list endpoint to find the correct plan key
- Ensure the plan belongs to your developer account
Important Notes¶
Plan Deletion
- Deleting a plan will cancel all active subscriptions
- Customers will be notified via email about the plan deletion
- This action cannot be undone
Test vs Production
- Use your Test Key (
sk_test_...) for development and testing - Use your Live Key (
sk_live_...) for real transactions - Query parameter
?test=trueor?test=falsecontrols the mode - The system automatically detects the mode based on the API Key used
Intervals
month- Monthly billingyear- Yearly billinginterval_countspecifies how many intervals (e.g., interval=month, interval_count=3 = every 3 months)
Trial Period
- Trial period is specified in days
- Set
trial_period_daysto 0 for no trial - During trial period, customers are not charged
- After trial expires, first charge is applied
Filtering
- Multiple filters can be combined
- Filters are applied with AND logic
- Search parameters use case-insensitive matching
Best Practices¶
- Clear plan names - Use descriptive names that clearly indicate the tier and features
- Accurate descriptions - Provide detailed descriptions of what’s included in each plan
- Appropriate pricing - Ensure prices are competitive and reflect the value provided
- Trial periods - Consider offering trial periods to reduce customer acquisition friction
- Test before production - Use test mode with test API keys for validation
- Monitor subscribers - Use the subscriber count in responses to track plan adoption
- Plan versioning - Create new plans instead of heavily modifying existing ones with subscribers
- Image optimization - Use optimized images to reduce API response times
Troubleshooting¶
Problem: “Plan does not exist”¶
Cause: Plan key doesn’t exist or belongs to a different developer account
Solution: - Verify the plan key using the list endpoint - Ensure you’re using the correct API Key - Check that the plan hasn’t been deleted
Problem: “Authentication credentials were not provided”¶
Cause: Missing or invalid API Key authentication
Solution: - Use Authorization: Api-Key sk_test_... header in your request - Verify your API Key is active - Test with Postman using the Api-Key authentication
Problem: “El precio mínimo no puede ser mayor que el máximo”¶
Cause: Invalid price range filter provided
Solution: - Ensure price_min ≤ price_max - Check the filter values are valid numbers
Problem: “El plan consultado no existe”¶
Cause: Query filters didn’t match any plans
Solution: - Verify filter parameters are correct - Try listing all plans without filters - Check if the plan exists in test mode (adjust test parameter)
FAQ¶
Q: Can I change the price of an existing plan?
A: No, plan pricing is immutable. Create a new plan with the updated price and migrate customers to it.
Q: What happens when I delete a plan?
A: All active subscriptions are cancelled and customers are notified. This action cannot be undone.
Q: Can I have multiple plans with the same name?
A: Yes, but it’s recommended to use unique names for easier management and identification.
Q: How many plans can I create?
A: There is no limit on the number of plans you can create.
Q: Can I update interval or interval_count after creation?
A: No, these are immutable. Create a new plan with the desired billing frequency.
Q: What’s the difference between interval and interval_count?
A: interval is the unit (month, year), and interval_count is the multiplier (e.g., every 3 months = interval=month, interval_count=3).
Q: Can I use the same plan for multiple products?
A: Yes, plans are independent of products. A plan represents a billing cycle configuration.
Q: How do I check the number of active subscribers for a plan?
A: Use the list or get endpoints. The information.count field shows active subscriptions.