Introduction
Intents are the primary way to perform business operations in Aviate. Rather than making many low-level API calls to create accounts, subscriptions, and invoices, you submit a single intent that describes what you want to achieve. The system plans the necessary steps, validates the operation, and executes it — all in a single, trackable request.
Key advantages of using intents:
-
Declarative operations — describe the desired outcome, not the individual steps
-
Built-in validation — intents are validated before execution, catching errors early
-
Audit trail — every intent is recorded with its full lifecycle, including who created it, when, and what changed
-
Approval integration — high-impact intents can require approval before execution
-
Preview mode — see what an intent will do before committing to it
Available Intent Types
| Intent Type | Description |
|---|---|
|
Create a new customer account with optional subscriptions, payment method, and custom fields |
|
Move a subscription to a higher-tier plan |
|
Move a subscription to a lower-tier plan |
|
Cancel a subscription (immediate, end of term, or specific date) |
|
Temporarily pause a subscription and its billing |
|
Resume a previously paused subscription |
|
Change a subscription to a different plan or billing period |
|
Add an add-on subscription to an existing base subscription |
|
Remove an add-on subscription |
|
Record usage for a metered subscription |
|
Apply a coupon to an account or subscription |
|
Apply a wallet credit to an account |
|
Create a new quote for a customer |
|
Accept a quote (converts it to an order) |
|
Create a new contract from a quote or order |
|
Renew an existing contract for a new term |
|
Terminate a contract |
|
Apply an adjustment to an invoice or invoice item |
|
A custom intent type for plugin-specific operations |
Intent Lifecycle
Every intent follows a well-defined lifecycle:
DRAFT -> VALIDATED -> PLANNED -> [PENDING_APPROVAL ->] APPROVED -> EXECUTING -> COMPLETED
-> FAILED
-> CANCELLED
| Status | Description |
|---|---|
|
Intent has been created but not yet validated |
|
Input parameters passed validation checks |
|
Execution plan has been computed (viewable via preview) |
|
Waiting for required approvals (if approval policy matches) |
|
All required approvals received (or no approval policy matched) |
|
The system is currently executing the planned steps |
|
All steps executed successfully |
|
One or more steps failed (partial changes may have been applied) |
|
Intent was cancelled before or during execution |
Getting Started
Submitting Your First Intent
The following example onboards a new customer with a subscription:
curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/intents" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}" \
-H "Content-Type: application/json" \
-d '{
"type": "ONBOARD_CUSTOMER",
"params": {
"account": {
"name": "Acme Corp",
"email": "[email protected]",
"externalKey": "acme-001",
"currency": "USD",
"locale": "en_US",
"timeZone": "America/Los_Angeles"
},
"subscriptions": [
{
"planName": "professional-monthly",
"externalKey": "acme-001-pro"
}
],
"paymentMethod": {
"pluginName": "killbill-stripe",
"pluginInfo": {
"properties": [
{ "key": "token", "value": "tok_visa" }
]
}
}
}
}'
Response:
{
"intentId": "int-a1b2c3d4",
"type": "ONBOARD_CUSTOMER",
"status": "COMPLETED",
"createdDate": "2026-03-15T10:30:00Z",
"completedDate": "2026-03-15T10:30:02Z",
"results": {
"accountId": "acc-x1y2z3",
"subscriptionIds": ["sub-m1n2o3"]
}
}
Previewing an Intent
Before executing an intent, you can preview what it will do:
curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/intents?dryRun=true" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}" \
-H "Content-Type: application/json" \
-d '{
"type": "UPGRADE_SUBSCRIPTION",
"params": {
"subscriptionExternalKey": "acme-001-pro",
"newPlanName": "enterprise-monthly"
}
}'
The response includes the planned steps without executing them:
{
"intentId": null,
"type": "UPGRADE_SUBSCRIPTION",
"status": "PLANNED",
"plan": {
"steps": [
{ "action": "CHANGE_PLAN", "target": "subscription/acme-001-pro", "detail": "professional-monthly -> enterprise-monthly" },
{ "action": "PRORATE_INVOICE", "target": "account/acme-001", "detail": "Credit $15.00, charge $45.00" }
],
"estimatedInvoiceAmount": 30.00
}
}
Flexible Entity References
Intents support multiple ways to reference existing entities, so you can use whichever identifier is most convenient:
| Reference Style | Example | When to Use |
|---|---|---|
UUID |
|
When you have the Kill Bill internal ID |
External key |
|
When you manage your own customer identifiers |
|
When looking up by email (accounts only) |
Only one reference is needed. If multiple are provided, the system verifies they all resolve to the same entity.
Upgrading a Subscription
curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/intents" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}" \
-H "Content-Type: application/json" \
-d '{
"type": "UPGRADE_SUBSCRIPTION",
"params": {
"subscriptionExternalKey": "acme-001-pro",
"newPlanName": "enterprise-monthly",
"effectiveDate": "2026-04-01"
}
}'
If an approval policy is configured for upgrades above a certain threshold, the intent enters PENDING_APPROVAL status instead of executing immediately. See the Approvals documentation for details.
Checking Intent Status
Get a Specific Intent
curl "${KB_URL}/plugins/aviate-plugin/v1/intents/int-a1b2c3d4" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}"
List Intents for an Account
curl "${KB_URL}/plugins/aviate-plugin/v1/intents?accountExternalKey=acme-001&limit=10" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}"
Status Snapshots
Each intent includes a conditions array that provides a Kubernetes-style status summary. This is useful for monitoring and debugging:
{
"intentId": "int-a1b2c3d4",
"status": "COMPLETED",
"conditions": [
{ "type": "Validated", "status": "True", "timestamp": "2026-03-15T10:30:00Z" },
{ "type": "Planned", "status": "True", "timestamp": "2026-03-15T10:30:00Z" },
{ "type": "Approved", "status": "True", "timestamp": "2026-03-15T10:30:01Z", "reason": "NoApprovalPolicyMatched" },
{ "type": "Executed", "status": "True", "timestamp": "2026-03-15T10:30:02Z" }
]
}
For failed intents, the conditions include error details:
{
"intentId": "int-x1y2z3",
"status": "FAILED",
"conditions": [
{ "type": "Validated", "status": "True", "timestamp": "2026-03-15T10:30:00Z" },
{ "type": "Planned", "status": "True", "timestamp": "2026-03-15T10:30:00Z" },
{ "type": "Executed", "status": "False", "timestamp": "2026-03-15T10:30:02Z",
"reason": "PaymentDeclined", "message": "Card ending 4242 was declined" }
]
}
Cancelling an Intent
A DRAFT, VALIDATED, PLANNED, or PENDING_APPROVAL intent can be cancelled:
curl -X POST "${KB_URL}/plugins/aviate-plugin/v1/intents/int-a1b2c3d4/cancel" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}"
Intents that are already EXECUTING, COMPLETED, or FAILED cannot be cancelled.
Audit Trail
Every intent records an audit log that includes:
-
The authenticated user who created the intent
-
Timestamps for each lifecycle transition
-
HTTP request and response details for each step executed
-
Any approval decisions (who approved or rejected, and when)
You can retrieve the full audit trail:
curl "${KB_URL}/plugins/aviate-plugin/v1/intents/int-a1b2c3d4/audit" \
-H "Authorization: Bearer ${ID_TOKEN}" \
-H "X-Killbill-ApiKey: ${API_KEY}" \
-H "X-Killbill-ApiSecret: ${API_SECRET}"