Getting started with the Alunta API

Use the public v1 API to integrate your own system with Alunta. The interactive API reference and OpenAPI document are the canonical contracts for individual endpoints and schemas.

Authentication and base URL

The API uses OAuth 2 access tokens. Send the token on every request:

Authorization: Bearer {access-token}
Accept: application/json
Content-Type: application/json

All v1 endpoints are below /api/v1. Access is limited to the Alunta team bound to the token, and available operations depend on its scopes and enabled API module.

Never place access tokens in logs, source control, URLs, or documentation. Store them in a secret manager and rotate them if exposed.

A first request

List customers to verify the connection:

GET /api/v1/customers

Use UUIDs returned by the API when addressing a specific resource. Do not rely on internal database IDs.

Create and send a one-off invoice

POST /api/v1/invoices creates and books a one-off invoice. It does not email the invoice to the customer. To send the PDF by email, make a separate request to POST /api/v1/invoices/{uuid}/send using the UUID returned in the create response. If you omit email, Alunta uses the customer's primary email address; provide email to send to a different address.

The send endpoint is an explicit manual action and can send even when automatic invoice emails or the customer's invoice-email preference are disabled. It does not change those preferences. A successful response means the email was accepted for queued delivery, not that delivery has completed. Each call queues a new email and the send endpoint has no idempotency key. If a request times out or delivery is uncertain, review the invoice and the customer's activity timeline in the Alunta UI, or contact Alunta support to confirm its status before trying again to avoid a duplicate email. The public API does not expose invoice email delivery status or mail logs. See the invoice API reference for request and response details.

Pagination and filtering

Collection endpoints can support pagination and filters. Follow the parameters and response shape documented for the specific endpoint in the OpenAPI reference. Do not assume that every collection accepts the same filters.

Errors

Use the HTTP status first, then inspect the JSON error response. Common statuses are:

Validation errors normally include field-specific details. Treat the exact OpenAPI response schema as authoritative.

Rate limits and retries

The v1 API allows up to 120 read requests (GET) and 600 write requests (POST, PUT, PATCH, DELETE) per minute per team. Reads and writes have separate quotas; all access tokens issued for the same team share them, and a user holding tokens for several teams gets a separate quota for each team. Separately, at most 12 requests per user and 14 across all callers are processed at the same moment; a request over a cap gets an immediate 429 with Retry-After: 1 and code: too_many_concurrent_requests (scope is user or global), so keep only a few requests in flight. Responses include rate-limit headers. When receiving 429 Too Many Requests, respect Retry-After and retry with exponential backoff. To detect changes, subscribe to webhooks rather than polling individual resources.

Retry only operations that are safe to repeat, unless the endpoint documents an idempotency mechanism. Apply bounded retries to transient 5xx and network failures.

Customers who already pay through your own Stripe account

If your product collects payment details itself with Stripe (for example a SetupIntent in your own signup flow), keep that flow and hand the payment method to Alunta. Card details never pass through Alunta.

  1. Connect the same Stripe account to Alunta under Settings -> Integrations -> Stripe. Alunta can only use payment methods from the connected account.
  2. Create or find the customer with POST /api/v1/customers.
  3. Attach the payment method with POST /api/v1/customers/{uuid}/payment-methods and {"stripe_payment_method_id": "pm_..."}. The payment method must be attached to a Stripe customer (create the SetupIntent with customer). Card, Link and SEPA Direct Debit are supported. A SEPA payment method also needs an active, reusable mandate from a successful off-session SetupIntent on the same connected account, and SEPA can only collect EUR amounts. The call is idempotent per payment method, and set_as_default (default true) makes it the customer's default.
  4. Create the subscription with POST /api/v1/subscriptions. With payment_provider: stripe, or with payment_provider omitted, it is charged on the customer's default payment method.

To change the card a customer pays with, attach the new payment method as the default and then delete the old one with DELETE /api/v1/customers/{uuid}/payment-methods/{paymentMethodUuid}. Subscriptions that were charged on the old one move to the new one. The delete is refused for the last payment method and while an active subscription would be left without a usable payment method from the same provider. GET /api/v1/customers/{uuid}/payment-methods lists what is on file.

When you move existing subscriptions from another billing system, send the next renewal date from that system as start_date, not the original start date: a start date in the past bills every elapsed period. Send apply_plan_trial: false and apply_plan_intro_offer: false so the plan's sign-up trial and intro offer do not apply, and an Idempotency-Key header so the import can be retried safely. Stop each subscription in the old system at the same time as you create it in Alunta, so a customer is never charged by both. Check the next charge with GET /api/v1/customers/{uuid}/upcoming-invoices for a few customers before moving the rest. See the customer and subscription API reference for every field and error code.

Usage parameters

Usage parameters define team-wide metered quantities such as messages, active users, or API calls. Counter parameters add deltas; gauge parameters replace the value for the timestamped period. Plans can use these measurements for usage-based or tiered billing. Usage sent to POST /subscriptions/{uuid}/usage is billed on that subscription and returns 422 with code subscription_not_started or subscription_ended when the recorded date is outside its term; a counter event sent to POST /customers/{uuid}/usage-events is billed on the customer's newest live subscription metering that parameter, and is stored but not billed (subscription_uuid null) when there is none.

To remove a mistaken counter event before billing or payment protects its period, call DELETE /api/v1/customers/{uuid}/usage-events/{eventUuid}. Success returns 204; an event already missing at lookup returns 404, and billing protection returns 409. Concurrent deletes that both found the event can both succeed with 204. Gauges cannot be deleted (422); report a new snapshot instead. To replace a counter event, record a new event with a new idempotency_key and the intended original recorded_at. The deleted key remains reserved for the existing window (about 30 days from original creation); reusing it returns 409 with usage_record_deleted. Delete and replacement are separate requests, so replacement can fail or billing can start between them.

The customer.usage_deleted webhook carries the removed record's usage_record snapshot for API and UI deletions. Dispatch is attempted after commit and does not block deletion on a listener or queue-handoff failure. Queued deliveries can be retried or arrive out of order; apply deletion by the record UUID and use GET /api/v1/customers/{uuid}/usage-events to reconcile current state.

Check the usage endpoints in the API reference for supported identifiers, timestamps, and request schemas.

Webhooks

Webhooks notify your HTTPS endpoint when supported events happen. Configure an endpoint and subscribe only to events you need.

The API includes delivery-log and replay operations for supported webhook deliveries. Keep your own audit trail of received event identifiers and outcomes.

Keep the integration current

Use the OpenAPI document for generated clients and contract tests. Review the public changelog for behavioral changes, and validate integrations against a non-production Alunta team before rollout.