curl --request POST \
--url https://app.saasybill.com/api/v1/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"customer_code": "ACME-001",
"plan_code": "TEAM-MONTHLY",
"units": 10,
"start_date": "2026-09-30",
"discount_percent": "10",
"label": "Acme – Team plan",
"invoice_reference": "PO-4471"
}
'{
"id": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"object": "subscription",
"customer": "3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11",
"customer_code": "ACME-001",
"plan": "b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44",
"status": "active",
"currency": "AUD",
"interval": {
"unit": "month",
"count": 1
},
"timezone": "Australia/Sydney",
"start_date": "2026-09-30",
"renewal_date": "2026-10-30",
"end_date": null,
"units": 10,
"minimum_units": 5,
"discount_percent": "10.00",
"cancel_at_period_end": false,
"end_after_cycles": null,
"label": "Acme – Team plan",
"invoice_reference": "PO-4471",
"renewal_value": "108.0000",
"created": "2026-09-30T04:12:00.000Z",
"invoice": {
"id": "5f8a3c9d-7e21-4b04-9c6d-0a2b4e8f1d55",
"object": "invoice",
"customer": "3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"number": "INV-0042",
"reference": "PO-4471",
"status": "awaiting_approval",
"currency": "AUD",
"invoice_date": "2026-09-29T14:00:00.000Z",
"due_date": "2026-10-29T13:00:00.000Z",
"subtotal": "558.0000",
"total": "613.8000",
"credit_note_amount": "0.0000",
"amount_paid": null,
"sent": false,
"xero": {
"sync_status": "synced",
"invoice_id": "f0e9d8c7-b6a5-4f43-9210-fedcba987654",
"sync_error": null
},
"lines": [
{
"id": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c77",
"type": "subscription",
"name": "Team",
"description": "Team – 10 seats",
"units": 10,
"amount": "120.0000",
"discount_amount": "12.0000",
"charge_amount": "108.0000",
"effective_date": "2026-09-29T14:00:00.000Z"
},
{
"id": "1b2c3d4e-5f6a-4b7c-9d8e-0f1a2b3c4d88",
"type": "charge",
"name": "Onboarding",
"description": "One-off setup and training",
"units": null,
"amount": "450.0000",
"discount_amount": "0.0000",
"charge_amount": "450.0000",
"effective_date": "2026-09-29T14:00:00.000Z"
}
],
"created": "2026-09-30T04:12:01.000Z"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Provide a valid API key as `Authorization: Bearer <key>`.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "permission_error",
"code": "insufficient_scope",
"message": "This API key does not have the `subscriptions:write` scope.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "not_found",
"code": "subscription_not_found",
"message": "There is no subscription with that id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "conflict",
"code": "idempotency_conflict",
"message": "This `Idempotency-Key` was used with a different request. Use a new key for a different request.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "`units`: Invalid input: expected number, received string",
"param": "units",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Too many requests. Try again in 12 seconds.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "api_error",
"code": "internal_error",
"message": "Something went wrong on our side. Retry the request; if it keeps failing, quote the request id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}Create a subscription
Creates the subscription and its first invoice, and sends the invoice to Xero, under the same rules as the New Subscription form. Idempotency-Key is required: a repeat of this request would otherwise be a second subscription and a second bill. A retry with the same key and body returns the first response. If Xero refuses the invoice the subscription still exists and the response is 201 with invoice.xero.sync_status of failed.
curl --request POST \
--url https://app.saasybill.com/api/v1/subscriptions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"customer_code": "ACME-001",
"plan_code": "TEAM-MONTHLY",
"units": 10,
"start_date": "2026-09-30",
"discount_percent": "10",
"label": "Acme – Team plan",
"invoice_reference": "PO-4471"
}
'{
"id": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"object": "subscription",
"customer": "3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11",
"customer_code": "ACME-001",
"plan": "b6c1e0a4-2f7d-4a61-8f0c-5d3e9a7b2c44",
"status": "active",
"currency": "AUD",
"interval": {
"unit": "month",
"count": 1
},
"timezone": "Australia/Sydney",
"start_date": "2026-09-30",
"renewal_date": "2026-10-30",
"end_date": null,
"units": 10,
"minimum_units": 5,
"discount_percent": "10.00",
"cancel_at_period_end": false,
"end_after_cycles": null,
"label": "Acme – Team plan",
"invoice_reference": "PO-4471",
"renewal_value": "108.0000",
"created": "2026-09-30T04:12:00.000Z",
"invoice": {
"id": "5f8a3c9d-7e21-4b04-9c6d-0a2b4e8f1d55",
"object": "invoice",
"customer": "3b9f1c1e-6a52-4c0e-9d7e-1f6f2f0b7a11",
"subscription": "9d4e2b7a-13c5-4f8e-b6a0-2e1d7c9f5b33",
"number": "INV-0042",
"reference": "PO-4471",
"status": "awaiting_approval",
"currency": "AUD",
"invoice_date": "2026-09-29T14:00:00.000Z",
"due_date": "2026-10-29T13:00:00.000Z",
"subtotal": "558.0000",
"total": "613.8000",
"credit_note_amount": "0.0000",
"amount_paid": null,
"sent": false,
"xero": {
"sync_status": "synced",
"invoice_id": "f0e9d8c7-b6a5-4f43-9210-fedcba987654",
"sync_error": null
},
"lines": [
{
"id": "0a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c77",
"type": "subscription",
"name": "Team",
"description": "Team – 10 seats",
"units": 10,
"amount": "120.0000",
"discount_amount": "12.0000",
"charge_amount": "108.0000",
"effective_date": "2026-09-29T14:00:00.000Z"
},
{
"id": "1b2c3d4e-5f6a-4b7c-9d8e-0f1a2b3c4d88",
"type": "charge",
"name": "Onboarding",
"description": "One-off setup and training",
"units": null,
"amount": "450.0000",
"discount_amount": "0.0000",
"charge_amount": "450.0000",
"effective_date": "2026-09-29T14:00:00.000Z"
}
],
"created": "2026-09-30T04:12:01.000Z"
}
}{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Provide a valid API key as `Authorization: Bearer <key>`.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "permission_error",
"code": "insufficient_scope",
"message": "This API key does not have the `subscriptions:write` scope.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "not_found",
"code": "subscription_not_found",
"message": "There is no subscription with that id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "conflict",
"code": "idempotency_conflict",
"message": "This `Idempotency-Key` was used with a different request. Use a new key for a different request.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "invalid_request_error",
"code": "invalid_parameter",
"message": "`units`: Invalid input: expected number, received string",
"param": "units",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Too many requests. Try again in 12 seconds.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}{
"error": {
"type": "api_error",
"code": "internal_error",
"message": "Something went wrong on our side. Retry the request; if it keeps failing, quote the request id.",
"request_id": "req_4f1a9c2e7b8d3a605e1c9f02"
}
}subscriptions:write scope. See Authentication.Authorizations
An API key. Its scopes decide what it may call: customers:read (List and look up customers.) customers:write (Create customers, and Xero contacts where the organisation allows it.) catalogue:read (List plans and charges.) subscriptions:read (List and look up subscriptions.) subscriptions:write (Create subscriptions, change units, end and restore them.) invoices:read (List and look up invoices.)
Headers
1 to 255 printable characters. A retry with the same key and body returns the first response.
1 - 255"signup_8f3a2c1d"
Body
The Saasybill customer id. Give this or customer_code.
1 - 100The organisation's own reference for the customer. Unique per organisation.
Create the customer in Xero if no customer has customer_code. Needs the organisation to have allowed it.
Show child attributes
Show child attributes
The plan id. Give this or plan_code.
1 - 1001 - 100Not for a flat fee plan.
0 <= x <= 999999999Only where the plan allows its price to be overridden.
1 - 20Defaults to today in the organisation's timezone.
^\d{4}-\d{2}-\d{2}$1 <= x <= 10000 to 100. Defaults to 0.
1 - 202552550 <= x <= 9999999991 - 201 <= x <= 36550Show child attributes
Show child attributes
Response
Success.
"subscription"pending, active, complete, ended Show child attributes
Show child attributes
YYYY-MM-DD, in the subscription's own timezone.
YYYY-MM-DD, in the subscription's own timezone.
YYYY-MM-DD, in the subscription's own timezone.
A decimal string, e.g. "19.9900".
A decimal string, e.g. "19.9900".
ISO 8601, UTC.
The first invoice. Null in setup mode, where none is raised. Check xero.sync_status.
Show child attributes
Show child attributes
Was this page helpful?