Skip to content
Coritan Docs

Make your first API request

Get an access token, list your services and refresh the token when it expires, with curl commands you can copy.

View as Markdown

This tutorial takes you from your email and password to a working API session in a terminal. You sign in, read your account, list your services and renew the access token when it runs out. Every request goes to https://api.coritan.com/api/v1.

Important

The API accepts the access token that signing in returns. It does not accept the keys from Settings, API keys (they start with ct_): a request that sends one answers 401. Manage API keys explains what the keys are for today.

1. Check whether sign-in needs a challenge

Section titled 1. Check whether sign-in needs a challenge

The sign-in page can ask for a bot check. Ask the API whether it is on:

Shell
curl https://api.coritan.com/api/v1/auth/turnstile
JSON
{"enabled": false, "site_key": ""}

When enabled is false, an email and a password are enough to sign in, and you can go on to the next section. When it is true, POST /auth/login also needs a turnstile_token that only the check on the sign-in page produces. Without one it answers 403 with {"detail": {"error": "turnstile_failed", "message": "Verification required"}}, so a script cannot sign in on its own.

You now know whether your password is enough to sign in from a terminal.

2. Sign in and keep the tokens

Section titled 2. Sign in and keep the tokens
  1. Read your password into a variable, so it stays out of your shell history:

    Shell
    read -rs -p "Password: " CORITAN_PASSWORD; echo
    
  2. Sign in with POST /auth/login. jq builds the JSON body, so a password with quotes or other special characters is sent intact:

    Shell
    curl -s -X POST https://api.coritan.com/api/v1/auth/login \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg email alex@example.com --arg password "$CORITAN_PASSWORD" '{email: $email, password: $password}')" \
      > login.json
    

    Without two-factor authentication, login.json holds your tokens:

    JSON
    {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "bearer",
      "expires_in": 1800
    }
    

    expires_in is how many seconds the access token lasts.

  3. If you use two-factor authentication, the answer asks for your code instead:

    JSON
    {"mfa_required": true, "mfa_setup_required": false, "mfa_token": "eyJhbGciOiJIUzI1NiIs...", "expires_in": 600, "token_type": "bearer"}
    

    Send the code from your app with POST /auth/mfa/verify within ten minutes, with mfa_token as the bearer token. A recovery code works too, once. The answer holds the same tokens as a sign-in without a second factor:

    Shell
    MFA_TOKEN=$(jq -r .mfa_token login.json)
    curl -s -X POST https://api.coritan.com/api/v1/auth/mfa/verify \
      -H "Authorization: Bearer $MFA_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"code": "123456"}' \
      > login.json
    
  4. Keep both tokens in variables:

    Shell
    export CORITAN_TOKEN=$(jq -r .access_token login.json)
    CORITAN_REFRESH=$(jq -r .refresh_token login.json)
    

echo "$CORITAN_TOKEN" now prints a long string that starts with eyJ. Keep login.json private or delete it: anyone with these tokens can use your account.

Send the access token in the Authorization header of every request. GET /auth/me returns the account the token belongs to:

Shell
curl -s https://api.coritan.com/api/v1/auth/me \
  -H "Authorization: Bearer $CORITAN_TOKEN"
JSON
{
  "id": 4821,
  "email": "alex@example.com",
  "first_name": "Alex",
  "last_name": null,
  "company": null,
  "status": "active",
  "billing_mode": "prepaid",
  "credit_balance": 25.0,
  "currency": "USD",
  "country_code": "GB",
  "currency_source": "default",
  "created_at": "2026-09-01T10:15:00"
}

The email is yours, which shows the token works. Update your profile describes each field.

GET /services/ returns a JSON array of the services on your account, newest first. This prints one line for each of the first five:

Shell
curl -s "https://api.coritan.com/api/v1/services/?limit=5" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  | jq -c '.[] | {id, hostname, status, product_name}'
JSON
{"id":1042,"hostname":"web-1.example.com","status":"active","product_name":"Cloud Compute 2 GB"}

An account with no services prints nothing. You see the same services as on the Services page. Manage your services lists the filters and fields.

When the access token runs out, every request answers 401 with Invalid or expired token. Exchange the refresh token for a new pair with POST /auth/refresh. It needs no password, no bot check and no second factor:

Shell
curl -s -X POST https://api.coritan.com/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg token "$CORITAN_REFRESH" '{refresh_token: $token}')" \
  > login.json
export CORITAN_TOKEN=$(jq -r .access_token login.json)
CORITAN_REFRESH=$(jq -r .refresh_token login.json)

The answer has the same fields as a sign-in. Keep the new refresh_token each time: it starts a full lifetime of its own, while the one you sent keeps its old expiry. When a refresh token has expired too, sign in again as in section 2.

Run the GET /auth/me request from section 3 again. It answers with your account, using the new token.

401 Invalid email or password
The email or the password is wrong. The answer is the same for both.
403 Account is suspended or closed
The account cannot sign in. Contact support.
401 That code is not right
The code is wrong, or you used it already: each code from the app works once. Wait for the next one.
401 Invalid or expired token from /auth/mfa/verify
The mfa_token is more than ten minutes old. Sign in again.
401 with "error": "mfa_required"
You sent the mfa_token to another endpoint. Finish section 2 first.
401 Token invalidated by password change
Someone changed the account's password after the token was issued. Sign in again with the new password.
403 Not authenticated
The request has no Authorization header. Check that $CORITAN_TOKEN is set in the shell you are using.
429 Too many authentication attempts. Please try again later.
Too many sign-in or refresh attempts failed from your address. Wait a minute, as the Retry-After header says.

API operations on this page

MethodPathWhat it does
GET/api/v1/auth/turnstileTurnstile config
POST/api/v1/auth/loginLogin
POST/api/v1/auth/mfa/verifySecond step of signing in
GET/api/v1/auth/meGet me
GET/api/v1/services/List services
POST/api/v1/auth/refreshRefresh