Appearance
Reseller API
For reseller teams: manage end customers, their logins and grants, read your discounts and the catalog, and order products that are charged right away.
All paths below are relative to:
text
https://console.anikeen.com/api/v1/reseller/teams/{team}Access
Tokens
Personal access tokens and OAuth logins of Anikeen ID. Refused with 401:
- client-credentials tokens (no user),
- tokens of apps Anikeen trusts acting for a user (
error: client_not_allowed) - they get scopes without a consent screen and only work in their own team (see Apps acting for users).
Scopes
A full scope includes reading its area; user, user:read and * never count - the token has to carry the reseller scope itself.
| Scope | Allows |
|---|---|
reseller-customers:read | every GET below |
reseller-customers | plus creating/changing/suspending customers, invitations, removing logins |
reseller-grants | reading and writing grants; also needed for an order item with grant |
reseller-orders | placing orders; reading catalog, discounts and orders |
Team
{team} must be a reseller team whose owner you are, or where you have the team role "customer management". Every other team - also one where you are a plain member or an end customer - answers 404.
State of the reseller
| Requirement | Applies to | Otherwise |
|---|---|---|
| accepted reseller terms | writes to customers, invitations, logins and grants | 403, error: reseller_terms_required |
| no offboarding | the same writes (suspending and unsuspending customers stays possible) | 403, error: reseller_offboarding |
| may order: not suspended, not offboarding, VAT ID verified | orders | 403, error: reseller_orders_blocked |
Audit
Every write is recorded in the reseller's audit log like in the Console, marked as made through the API with the token and client.
Errors carry {"message": …, "error": "<code>"} where a code is listed.
Endpoints
| Method | Path | Scope (any of) | Notes |
|---|---|---|---|
| GET | /customers | customers:read, customers | ?search=, ?reference=, ?suspended=0/1, ?per_page= (max 100) |
| POST | /customers | customers | name (required), company, email, reference, notes → 201 |
| GET | /customers/{customer} | customers:read, customers | |
| PUT/PATCH | /customers/{customer} | customers | same fields; customers are never deleted |
| POST | /customers/{customer}/suspend | customers | its logins lose access, grants stay |
| POST | /customers/{customer}/unsuspend | customers | |
| GET | /customers/{customer}/invitations | customers:read, customers | status: open, expired, accepted |
| POST | /customers/{customer}/invitations | customers | email → 201; an open invitation to the same address is sent again (200) |
| POST | /customers/{customer}/invitations/{invitation}/resend | customers | new link, new expiry (7 days) |
| DELETE | /customers/{customer}/invitations/{invitation} | customers | revoke; accepted ones: 409 |
| GET | /customers/{customer}/logins | customers:read, customers | |
| DELETE | /customers/{customer}/logins/{user} | customers | the login keeps its account and own teams |
| GET | /grants | customers:read, customers, grants | ?customer_id=, ?product_type= (family, e.g. server), ?product_id= |
| POST | /grants | grants | customer_id, product_type, product_id, level → 201, or 200 when the grant existed (level changed) |
| GET | /grants/{grant} | customers:read, customers, grants | |
| PUT/PATCH | /grants/{grant} | grants | level |
| DELETE | /grants/{grant} | grants | |
| GET | /discounts | customers:read, customers, orders | current per family (* = all) and every entry; read only |
| GET | /catalog | customers:read, customers, orders | see Catalog |
| GET | /orders | customers:read, customers, orders | ?status= |
| POST | /orders | orders (+ grants for items with grant) | see Orders |
| GET | /orders/{order} | customers:read, customers, orders | the state of an order and its items |
Scope names in the table are shortened: customers:read = reseller-customers:read, and so on.
Customers and invitations
bash
curl -X POST https://console.anikeen.com/api/v1/reseller/teams/$TEAM/customers \
-H "Authorization: Bearer $ANIKEEN_TOKEN" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name":"Erika Mustermann","company":"Example GmbH","email":"erika@example.de","reference":"K-1001"}'A customer gets access through logins: invite an e-mail address with POST /customers/{customer}/invitations; whoever accepts becomes a login of that customer.
Grants
A grant gives a customer access to one of your products. Each level includes the ones before it:
level | Allows |
|---|---|
view | status and charts |
console | plus console, panel login, password reset |
power | plus start, stop, restart, reinstall |
manage | plus configuration: DNS records, mailboxes, firewall, backups, … |
Ordering, resizing, deleting, cancelling and transferring are never allowed for customers.
json
{"customer_id": "01JD…", "product_type": "server", "product_id": "01JD…", "level": "power"}Catalog
GET /catalog lists the orderable products per family at your reseller price, with the choices for the order attributes. Families: server, floatingIp, domain, zone, hosting, objectStorage, and container beta (while containers are rolled out for your user or team).
monthly_price, and thecatalog filters apply.
Orders
Orders are charged right away to the team owner's default payment method on Anikeen ID, without a confirmation there, at the reseller price. Coupons are not accepted. The products are set up in the background - poll GET /orders/{order} (there is no webhook and no cancellation through the API).
http
POST /v1/reseller/teams/{team}/orders
Idempotency-Key: 7b0c4c2e-…
Content-Type: application/json
{"items": [{
"family": "server",
"product_id": "01JC…",
"attributes": {"location_id": "bon1", "operating_system_id": "01JC…", "vlan_id": "01JC…",
"ssh_key": "01JC…", "username": "root", "name": "web-01.example.com"},
"grant": {"customer_id": "01JD…", "level": "power"}
}]}- Up to 10 items.
familyandproduct_idfromGET /catalog;attributesper family - see Order attributes. grant(optional, needsreseller-grants): the product is granted to that end customer at that level once it is built.
Responses
| Status | |
|---|---|
201 | the order: status: completed = charged; items pending → provisioned with product: {type, id}, or failed = not built, refunded |
202 | a retry of a request that was interrupted after its order was recorded: that order as it stands now (see Idempotency) |
422 | validation (errors keyed like items.0.attributes.location_id); nothing charged |
409 owner_sign_in_required | the owner's Anikeen ID login expired - the owner must sign in to the Console once; nothing charged |
409 order_refused | e.g. no default billing address or payment method |
402 order_failed | the charge failed (order holds the failed order, every subscription was revoked) |
429 rate_limited | more than 10 orders per minute and team (Retry-After); replays don't count |
Idempotency-Key is required - see Idempotency. The general limit of 60 requests per minute and user applies as well.