CoreInto

The API

CoreInto has a JSON API so other programs, such as your website, a control panel or a script, can read and change records: clients, orders, services, domains, invoices, payments, tickets and more.

CoreInto developer guide: The API overview with the main sections of the article

CoreInto has a JSON API so other programs, such as your website, a control panel or a script, can read and change records: clients, orders, services, domains, invoices, payments, tickets and more. A program signs in with an API credential made under Settings > API Credentials, calls an action at /api/v1/ACTION, and gets a JSON answer. Every call is checked against the credential's scopes, is limited to the addresses and the expiry you set, and is written to the API log. This chapter covers the credentials, how to call the API, the answers and errors, and a reference of every action.

Settings > API Credentials

The list shows each credential's description, identifier, the administrator it acts as, its access (Everything, or how many areas), allowed addresses, when and from where it was last used, and when it expires. The API Reference button opens the in-app reference page, which repeats the table at the end of this chapter with your own API address filled in.

Add Credential asks for:

FieldWhat it does
DescriptionWhat the credential is for, for example "website order form".
Acts as administratorChanges made through the API are written to the activity log under this administrator's name ("API: username"), and disabling the administrator stops the credential. You can only choose an enabled administrator whose permissions you hold yourself (see Staff and security). The choice is fixed once the credential is made.
Allowed addressesOne IP address or range per line, for example 203.0.113.7 or 198.51.100.0/24. Empty means any address.
Expires onA date after today. Empty means the credential never expires. On and after that date the credential stops working.
What it may reachTick Everything, or the scopes the credential needs (see below). At least one.

When the credential is created, the page shows the identifier (32 characters) and the secret once. Copy the secret then: CoreInto keeps only its SHA-256 fingerprint and cannot show it again. If it is lost, open the credential and press Make New Secret, which gives a new secret and stops the old one. Delete removes the credential; programs using it can no longer connect.

Scopes

A scope is an area of the API. An action needs the scope shown in the reference; system.whoami needs none.

ScopeAllows
clients:readRead clients, users and contacts
clients:writeAdd and change clients, users and contacts
orders:readRead orders
orders:writePlace, accept and cancel orders
services:readRead services and add-ons (and licences)
services:writeChange services and run module commands (and reissue licences)
domains:readRead domains
domains:writeChange domains and run registrar commands
billing:readRead invoices, transactions, credit and quotes
billing:writeCreate invoices, add payments and credit
support:readRead tickets, departments and announcements
support:writeOpen and reply to tickets
products:readRead products, prices and promotions
system:readRead the system counts
system:writeSend email and log activity

Calling the API

Address

Calls go to your site's address followed by /api/v1/ and the action:

https://www.example.com/api/v1/clients.get

Short addresses need the .htaccess rewrite that comes with CoreInto (Apache and LiteSpeed). Where addresses cannot be rewritten, name the action as a parameter instead:

https://www.example.com/api/index.php?action=clients.get

The action field may also be sent in the request body.

Signing in

Send the identifier and secret in the Authorization header:

Authorization: Bearer IDENTIFIER:SECRET

If your web server drops the Authorization header, send them as the fields identifier and secret instead (in the JSON body, the form or the query string). They are removed from the parameters before the action runs and never written to the log.

A credential is accepted when the identifier and secret match, its administrator is enabled, it has not expired, and the caller's address is in its allowed list (or the list is empty). Each successful sign-in records the time and address as "last used".

Parameters

Parameters go in one of three places, in this order of preference:

  1. A JSON object in the request body, with Content-Type: application/json.
  2. Form fields (application/x-www-form-urlencoded or multipart).
  3. The query string. Query values sit beneath the body: a name given in both takes the body's value.

Conventions:

  • Money is text with two decimals, such as "1500.00". Dates are YYYY-MM-DD.
  • Yes/no values accept 1, true, yes or on for yes; anything else is no.
  • Lists (such as items, lines or nameservers) are JSON arrays; in a form or query string they may be a JSON text or, for simple lists, comma-separated.
  • List actions take limit (1 to 250, default 50) and offset (default 0) and return total, offset, count and the rows.
  • Actions that change data must be called with POST; reading actions may use GET or POST.
  • Ids are returned as numbers. Columns holding passwords, secrets, access keys and the like are never returned.

Answers

Every answer is JSON with a matching HTTP status. Success:

{"result": "success", "client": {"id": 1001, "first_name": "Sara", ...}}

Failure:

{"result": "error", "message": "There is no such client."}
HTTP statusMeaning
200Success.
400Wrong or missing input; the message says which parameter. Also an action name missing or a body that is not valid JSON.
401Not signed in: no credential given, or it was not accepted (wrong, expired, from an address it may not use, or its administrator is disabled).
403The credential lacks the scope the action needs.
404No such action, or no such record.
405The action changes data and was not called with POST.
409The request is understood but cannot be carried out now, for example accepting an order that is not pending, or a payment on a cancelled invoice.
429Too many failed sign-ins from this address; wait 15 minutes.
500Something went wrong in CoreInto; the details are in the error log.
503CoreInto is not installed yet, or a database update is waiting for an administrator to apply it in the admin area.

Rate limiting

After 10 failed sign-ins from one address within 15 minutes, that address is refused for 15 minutes with status 429. IPv6 callers are counted by their /64 network. A successful sign-in clears the count. There is no limit on successful calls.

The API log

Every call, successful or not, is written to Utilities > API Log with the credential, action, address, HTTP status, time taken, the parameters and the answer. Parameters whose names contain pass, secret, token, epp or auth are stored as "(hidden)". The log can be filtered by date, action, address and failed calls only, and old entries can be removed under System Cleanup. The setting "Log every API call" on the Security tab of General Settings has no effect in this version: calls are always logged.

Examples

Who am I, with GET:

curl https://www.example.com/api/v1/system.whoami \
  -H "Authorization: Bearer 3f9c2b7e1a4d4c6f8e0b2a1d9c7e5f31:kq8Zr2vN0tXy5WbLm3Hc7dPa9Rs1Ue4Fg6"

A client by email address, with JSON parameters:

curl -X POST https://www.example.com/api/v1/clients.get \
  -H "Authorization: Bearer IDENTIFIER:SECRET" \
  -H "Content-Type: application/json" \
  -d '{"email": "sara@example.com"}'

Place an order for one product and one domain, and email the confirmation:

curl -X POST https://www.example.com/api/v1/orders.add \
  -H "Authorization: Bearer IDENTIFIER:SECRET" \
  -H "Content-Type: application/json" \
  -d '{"client_id": 1001, "email": true,
       "items": [
         {"type": "product", "product_id": 3, "term": "annually", "domain": "example.com"},
         {"type": "domain", "name": "example.com", "action": "register", "years": 1}
       ]}'

Record a bank transfer against an invoice, as form fields:

curl -X POST https://www.example.com/api/v1/invoices.add_payment \
  -H "Authorization: Bearer IDENTIFIER:SECRET" \
  -d invoice_id=5012 -d amount=49.00 -d gateway=banktransfer -d transaction_id=TRF-20261009-17

Where addresses cannot be rewritten, and the Authorization header is dropped by the server:

curl "https://www.example.com/api/index.php?action=tickets.list&open_only=1" \
  -d identifier=IDENTIFIER -d secret=SECRET

Reference

Parameters marked with * are required. "Changes data" means the action must be called with POST.

System

ActionScopeParametersReturns
system.whoaminonecredential (id, description, scopes, expires_on), staff (the administrator's username), version, time. Useful to test a connection.
system.statssystem:readstats: clients_active, orders_pending, services_active, domains_active, invoices_unpaid, invoices_overdue, tickets_awaiting_reply, cancellation_requests.
email.send (changes data)system:writeclient_id*; then either template (the name of an email template) with vars (an object of merge fields), or subject and message (merge fields such as {{client_first_name}} work)email_id. 409 when the email was not sent: the template is turned off, the client turned that kind of email off, or the address is not valid.
activity.add (changes data)system:writedescription*, client_idNothing more; the line is in the activity log under the credential's administrator.

Clients

ActionScopeParametersReturns
clients.listclients:readsearch (name, company or email contains), email (exact), status (active, inactive, closed), limit, offsetclients, newest first: id, first_name, last_name, company, email, phone, country, status, currency_id, group_id, credit, created_at.
clients.getclients:readid, or emailclient: every profile field, plus currency (code), users (id, email, names, is_owner, permissions), contacts, and counts of what the account holds.
clients.add (changes data)clients:writefirst_name*, last_name*, email*, country*, company, address1, address2, city, state, postcode, phone, tax_id, currency_id (else chosen by country), group_id, password (else a random one), marketing, send_welcome, allow_duplicate_emailclient_id, user_id, existing_user (true when a user with that email existed and became the owner). 409 when a client with that email exists and allow_duplicate_email is not set.
clients.update (changes data)clients:writeid*; any profile field; status (active, inactive, closed); group_id (0 for none); marketing; the flags tax_exempt, late_fee_exempt, overdue_notices_off, separate_invoices, auto_capture_off, auto_close_exempt, allow_ssochanged: the fields that changed. Only the fields sent change. 409 when another client has the new email address.
clients.close (changes data)clients:writeid*Nothing more; the account is closed.
clients.credit (changes data)billing:writeclient_id*, amount* (negative to take credit away), description*credit: the new balance. 409 when taking away more than the client has.
contacts.listclients:readclient_id*contacts.

Catalogue

ActionScopeParametersReturns
products.listproducts:readgroup_id, include_hidden (also hidden and retired products)products: id, group_id, group_name, type, name, slug, short_description, pay_type, hidden, retired, module, stock_control, stock_qty, and prices as currency code, then term, then setup and price.
tlds.listproducts:readtlds: id, tld, registrar, terms, auto_register, docs_required, epp_required, and register, transfer and renew price tables by currency and term (y1 to y10).
promotions.listproducts:readpromotions: id, code, type, value, recurring, starts_on, expires_on, max_uses, uses, notes.

Orders

ActionScopeParametersReturns
orders.listorders:readclient_id, status, limit, offsetorders, newest first: id, number, client_id, status, amount, currency, gateway, invoice_id, promo_code, source, created_at.
orders.getorders:readid*order with its items.
orders.add (changes data)orders:writeclient_id*, items* (see below), promo (a promotion code), gateway (a payment method name), notes, invoice (default true: make the invoice), email (send the order confirmation), accept (accept the order at once), setup (with accept: set products up on their servers now)order_id, order_number, invoice_id (null when nothing is billed), service_ids, domain_ids. Prices come from the catalogue; nothing the caller sends is used as a price. 400 with the reason when an item cannot be ordered.
orders.accept (changes data)orders:writeid*, setup (default true), email (default true: welcome emails)welcome_emails: how many were sent. 409 unless the order is Pending.
orders.cancel (changes data)orders:writeid*, fraud (mark as fraud instead)Nothing more; pending items and the unpaid invoice are cancelled. 409 when already cancelled.

Items for orders.add are objects in a list. A product:

{"type": "product", "product_id": 1, "term": "monthly", "qty": 1, "domain": "example.com",
 "options": {"4": 2}, "addons": [3], "ns1": "", "ns2": ""}

options maps a configurable option id to the chosen value id (or quantity); addons lists add-on ids. A domain:

{"type": "domain", "name": "example.com", "action": "register", "years": 1, "epp": "", "nameservers": []}

action is register or transfer; epp is the transfer code.

Services

ActionScopeParametersReturns
services.listservices:readclient_id, product_id, server_id, status, domain, limit, offsetservices, newest first: id, client_id, order_id, product_id, product, server_id, status, domain, username, billing_cycle, first_amount, recurring_amount, reg_date, next_due_date.
services.getservices:readid*service with options (option_id, name, value, qty) and addons (id, addon_id, name, status, billing_cycle, recurring_amount, next_due_date).
services.update (changes data)services:writeid*; domain, username, status (pending, active, suspended, terminated, cancelled, fraud, completed), billing_cycle, first_amount, recurring_amount, next_due_date, next_invoice_date, reg_date, termination_date, server_id (0 for none), dedicated_ip, assigned_ips, suspend_reason, noteschanged. Changes the record only, not the account on the server.
services.command (changes data)services:writeid*, command* (create, suspend, unsuspend, terminate, change_package, change_password), reason (for suspend), password* (for change_password), email (default true: send the matching client email)message from the module. 409 with the module's message when it fails.

Licences

These belong to the Licensing Manager add-on; see Licensing Manager.

ActionScopeParametersReturns
licenses.listservices:readclient_id, service_id, status (active, reissued, suspended, expired), limit, offsetlicenses, newest first: id, service_id, client_id, license_key, status, allowed_ips, allowed_hosts, allowed_dirs (lists), max_ips, reissues, last_check_at, last_ip, last_version, created_at.
licenses.getservices:readid, key or service_idlicense with its last 20 checks (created_at, result, ip, host, dir, version).
licenses.reissue (changes data)services:writeid, key or service_id; count_for_client (count it towards the client's own reissue limit)license after the reissue: its addresses, domains and folders are cleared and the next check binds it again.

Domains

ActionScopeParametersReturns
domains.listdomains:readclient_id, status, registrar, name, expires_before (a date), limit, offsetdomains, newest first: id, client_id, order_id, name, type, registrar, status, period_years, first_amount, recurring_amount, reg_date, expiry_date, next_due_date, auto_renew, nameservers.
domains.getdomains:readid, or namedomain.
domains.checkdomains:readname* (a full domain name)name, available (true, false, or null when it cannot be told), sold_here (whether you sell the extension).
domains.update (changes data)domains:writeid*; status, registrar, period_years (1 to 10), first_amount, recurring_amount, reg_date, expiry_date, next_due_date, next_invoice_date, auto_renew, dns_mgmt, email_fwd, id_protect, noteschanged. Changes the record only, not the domain at the registrar.
domains.command (changes data)domains:writeid*, command* (register, transfer, renew, sync, nameservers, lock, unlock, send_epp), years (for renew, 1 to 10), nameservers (a list, for nameservers)message from the registrar. 409 with the registrar's message when it fails. send_epp asks the registrar for the transfer code and emails it to the client (or passes the request to staff when the extension is handled by hand).

Billing

ActionScopeParametersReturns
invoices.listbilling:readclient_id, status, issued_from, issued_to, due_before, limit, offsetinvoices, newest first: id, number, client_id, status, issued_on, due_on, paid_at, currency, subtotal, tax1, tax2, credit, total, gateway.
invoices.getbilling:readid*invoice with currency, balance, lines (id, kind, rel_id, description, amount, taxed, due_on) and transactions (id, paid_at, gateway, trans_id, amount_in, fees, amount_out, description).
invoices.create (changes data)billing:writeclient_id*, lines* (a list of {"description": "...", "amount": "10.00", "taxed": true}), due_on (default today plus "Days to pay a new order"), gateway, notes, draft (make a draft instead of an unpaid invoice), apply_credit (use the client's credit on it), send (email it, unless a draft)invoice_id, number, total, status.
invoices.update (changes data)billing:writeid*, due_on, notes, status (unpaid, cancelled, collections, payment_pending)changed. Payments mark invoices paid; this action cannot. 409 when the invoice is paid.
invoices.add_payment (changes data)billing:writeinvoice_id*, amount* (more than zero), gateway* (a payment method name), transaction_id, date (default now), fees, send_receipt (default true)transaction_id (CoreInto's), status (the invoice's status after the payment), balance, to_credit (any overpayment added to the client's credit). A fully paid invoice sets its services and domains in motion like any payment. 409 when the invoice is a draft, cancelled or refunded, or when the same gateway transaction id was recorded before.
invoices.send (changes data)billing:writeid*, template (an invoice email, default invoice_created)email_id. 409 when the email was not sent.
transactions.listbilling:readclient_id, invoice_id, gateway, transaction_id, from, to (dates), limit, offsettransactions, newest first: id, client_id, invoice_id, gateway, trans_id, paid_at, currency, amount_in, fees, amount_out, description, refund_of.
quotes.listbilling:readclient_id, limit, offsetquotes, newest first.
quotes.getbilling:readid*quote with its lines.

Support

ActionScopeParametersReturns
tickets.listsupport:readclient_id, department_id, status, email, open_only (statuses that count as open), limit, offsettickets, latest reply first: id, mask (the ticket number), department_id, department, client_id, name, email, subject, status, priority, staff_id, last_reply_at, created_at. Merged tickets are left out.
tickets.getsupport:readid, or mask; include_notesticket with messages (id, user_id, contact_id, staff_id, name, email, body, format, rating, created_at) and, with include_notes, the staff notes.
tickets.open (changes data)support:writedepartment_id*, subject*, message*; client_id, or name and email (a guest ticket); priority (low, medium, high), format (markdown or plain), as_staff (the credential's administrator writes it; the ticket starts Answered), notify (with as_staff: email the ticket, default true)ticket_id, mask. Without as_staff the ticket is treated as opened by the client or guest: it starts Open, the automatic reply goes to them and staff are told.
tickets.reply (changes data)support:writeid or mask, message*, status (the status to set afterwards), format, as_client (reply as the ticket's client or guest instead of staff), notify (default true)message_id.
tickets.update (changes data)support:writeid or mask; status, priority, subject, department_id, staff_id (0 for nobody), flaggedchanged.
departments.listsupport:readdepartments: id, name, description, email, hidden, clients_only, sort.
announcements.listsupport:readlimit, offsetannouncements, newest first: id, title, body (Markdown), published_at. Only published ones.

Frequently asked questions

What does "The API" cover in CoreInto?

CoreInto has a JSON API so other programs, such as your website, a control panel or a script, can read and change records: clients, orders, services, domains, invoices, payments, tickets and more. CoreInto has a JSON API so other programs, such as your website, a control panel or a script, can read and change records: clients, orders, services, domains, invoices, payments, tickets and more. A program signs in with an API credential made under Settings > API Credentials, calls an action at /api/v1/ACTION, and gets a JSON answer. Every call is checked against the credential's scopes, is limited to the addresses and the expiry you set, and is written to the API log. This chapter covers the credentials, how to call the API, the answers and errors, and a reference of every action.

Where do I find more help?

Use the Help button on this site, browse the Developer guide on coreinto.com, or submit a ticket at https://system.coreinto.com/contact with your panel version and the steps you tried.

Submit a ticket