> ## Documentation Index
> Fetch the complete documentation index at: https://developers.phonovation.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authenticate with the Phonovation SMS API using OAuth 2.0 JWT tokens.

The Phonovation SMS API v2 uses **OAuth 2.0 password grant** to issue short-lived JWT access tokens. Every API request must include a valid token in the `Authorization` header.

```mermaid title="Authentication flow" theme={"dark"}
flowchart LR
  App["Developer app"] --> Auth["Auth server"]
  Auth --> Token["Access token"]
  Token --> API["Phonovation SMS API"]
  API --> Success["Authorized response"]
  API --> Expired["401 Unauthorized"]
  Expired --> Auth
```

## Step 1: Obtain a token

Send a `POST` request to the auth server with your credentials:

<CodeGroup>
  ```bash title="cURL" icon="terminal" wrap theme={"dark"}
  curl -X POST https://auth.interactsms.com/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=password&client_id=ismstoken&username=YOUR_USERNAME&password=YOUR_PASSWORD"
  ```

  ```python title="Python" icon="python" lines focus={3-13} theme={"dark"}
  import requests

  res = requests.post(
      "https://auth.interactsms.com/token",
      data={
          "grant_type": "password",
          "client_id": "ismstoken",
          "username": "YOUR_USERNAME",
          "password": "YOUR_PASSWORD"
      }
  )

  print(res.json())
  ```

  ```csharp title="C#" icon="code" lines focus={5-13} theme={"dark"}
  using System.Net.Http;

  using var client = new HttpClient();

  var body = new FormUrlEncodedContent(new Dictionary<string, string>
  {
      ["grant_type"] = "password",
      ["client_id"] = "ismstoken",
      ["username"] = "YOUR_USERNAME",
      ["password"] = "YOUR_PASSWORD"
  });

  var res = await client.PostAsync("https://auth.interactsms.com/token", body);
  Console.WriteLine(await res.Content.ReadAsStringAsync());
  ```

  ```java title="Java" icon="java" lines focus={8-18} theme={"dark"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URLEncoder;
  import java.nio.charset.StandardCharsets;

  String form = "grant_type=password"
      + "&client_id=ismstoken"
      + "&username=" + URLEncoder.encode("YOUR_USERNAME", StandardCharsets.UTF_8)
      + "&password=" + URLEncoder.encode("YOUR_PASSWORD", StandardCharsets.UTF_8);

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://auth.interactsms.com/token"))
      .header("Content-Type", "application/x-www-form-urlencoded")
      .POST(HttpRequest.BodyPublishers.ofString(form))
      .build();

  HttpResponse<String> res = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
  System.out.println(res.body());
  ```

  ```php title="PHP" icon="php" lines focus={3-12} theme={"dark"}
  $client = new GuzzleHttp\Client();

  $res = $client->post('https://auth.interactsms.com/token', [
      'form_params' => [
          'grant_type' => 'password',
          'client_id' => 'ismstoken',
          'username' => 'YOUR_USERNAME',
          'password' => 'YOUR_PASSWORD',
      ],
  ]);

  echo $res->getBody();
  ```

  ```js title="JavaScript" icon="js" lines focus={1-12} theme={"dark"}
  const res = await fetch("https://auth.interactsms.com/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "password",
      client_id: "ismstoken",
      username: "YOUR_USERNAME",
      password: "YOUR_PASSWORD",
    }),
  });

  console.log(await res.json());
  ```
</CodeGroup>

**Successful response:**

```json title="Token response" icon="code" highlight={2,5} wrap theme={"dark"}
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 120,
  "refresh_expires_in": 1200,
  "refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "scope": "email profile client_id"
}
```

<Warning>
  Access tokens expire after **120 seconds**. Refresh tokens expire after **1200 seconds**. Build token refresh logic into your integration.
</Warning>

## Step 2: Use the token

Pass the `access_token` as a Bearer token in all API requests:

<CodeGroup>
  ```bash title="cURL" icon="terminal" highlight={2} wrap theme={"dark"}
  curl https://api.interactsms.com/api/v2/senderlist \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```python title="Python" icon="python" lines focus={3-6} theme={"dark"}
  import requests

  res = requests.get(
      "https://api.interactsms.com/api/v2/senderlist",
      headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
  )

  print(res.json())
  ```

  ```csharp title="C#" icon="code" lines focus={5-8} theme={"dark"}
  using System.Net.Http.Headers;

  using var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");

  var res = await client.GetAsync("https://api.interactsms.com/api/v2/senderlist");

  Console.WriteLine(await res.Content.ReadAsStringAsync());
  ```

  ```java title="Java" icon="java" lines focus={6-10} theme={"dark"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.interactsms.com/api/v2/senderlist"))
      .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
      .GET()
      .build();

  HttpResponse<String> res = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
  System.out.println(res.body());
  ```

  ```php title="PHP" icon="php" lines focus={3-5} theme={"dark"}
  $client = new GuzzleHttp\Client();

  $res = $client->get('https://api.interactsms.com/api/v2/senderlist', [
      'headers' => ['Authorization' => 'Bearer YOUR_ACCESS_TOKEN'],
  ]);

  echo $res->getBody();
  ```

  ```js title="JavaScript" icon="js" lines focus={1-5} theme={"dark"}
  const res = await fetch("https://api.interactsms.com/api/v2/senderlist", {
    headers: {
      Authorization: "Bearer YOUR_ACCESS_TOKEN",
    },
  });

  console.log(await res.json());
  ```
</CodeGroup>

## Token expiry & refresh strategy

| Token           | Expiry       |
| --------------- | ------------ |
| `access_token`  | 120 seconds  |
| `refresh_token` | 1200 seconds |

Because tokens are short-lived, the recommended approach is to **re-authenticate before each request** or implement proactive refresh. The safest pattern is to catch a `401 Unauthorized` response and immediately re-authenticate with your credentials before retrying the request.

<CodeGroup>
  ```bash title="cURL" icon="terminal" lines expandable focus={2-11,13-14} theme={"dark"}
  ACCESS_TOKEN=$(
    curl -s -X POST https://auth.interactsms.com/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "grant_type=password&client_id=ismstoken&username=$ISMSAPI_USERNAME&password=$ISMSAPI_PASSWORD" \
    | jq -r '.access_token'
  )

  curl https://api.interactsms.com/api/v2/senderlist \
    -H "Authorization: Bearer $ACCESS_TOKEN"
  ```

  ```js title="JavaScript" icon="js" lines expandable focus={2-14} theme={"dark"}
  async function getToken() {
    const res = await fetch('https://auth.interactsms.com/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'password',
        client_id: 'ismstoken',
        username: process.env.ISMSAPI_USERNAME,
        password: process.env.ISMSAPI_PASSWORD
      })
    });
    const { access_token } = await res.json();
    return access_token;
  }

  async function apiRequest(path, options = {}) {
    const token = await getToken();
    const res = await fetch(`https://api.interactsms.com${path}`, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    });
    if (res.status === 401) throw new Error('Authentication failed');
    return res.json();
  }
  ```

  ```python title="Python" icon="python" lines expandable focus={3-14} theme={"dark"}
  import os, requests

  def get_token():
      res = requests.post(
          'https://auth.interactsms.com/token',
          data={
              'grant_type': 'password',
              'client_id': 'ismstoken',
              'username': os.environ['ISMSAPI_USERNAME'],
              'password': os.environ['ISMSAPI_PASSWORD']
          }
      )
      return res.json()['access_token']

  def api_request(path, **kwargs):
      token = get_token()
      res = requests.request(
          url=f'https://api.interactsms.com{path}',
          headers={'Authorization': f'Bearer {token}'},
          **kwargs
      )
      res.raise_for_status()
      return res.json()
  ```

  ```csharp title="C#" icon="code" lines expandable focus={5-16,18-32} theme={"dark"}
  using System.Net.Http.Headers;
  using System.Text.Json;

  using var client = new HttpClient();

  async Task<string> GetToken()
  {
      var body = new FormUrlEncodedContent(new Dictionary<string, string>
      {
          ["grant_type"] = "password",
          ["client_id"] = "ismstoken",
          ["username"] = Environment.GetEnvironmentVariable("ISMSAPI_USERNAME")!,
          ["password"] = Environment.GetEnvironmentVariable("ISMSAPI_PASSWORD")!
      });

      var res = await client.PostAsync("https://auth.interactsms.com/token", body);
      var json = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
      return json.RootElement.GetProperty("access_token").GetString()!;
  }

  async Task<string> ApiRequest(string path)
  {
      var token = await GetToken();
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

      var res = await client.GetAsync($"https://api.interactsms.com{path}");
      if ((int)res.StatusCode == 401) throw new Exception("Authentication failed");
      return await res.Content.ReadAsStringAsync();
  }
  ```

  ```java title="Java" icon="java" lines expandable focus={8-29,31-41} theme={"dark"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URLEncoder;
  import java.nio.charset.StandardCharsets;

  HttpClient client = HttpClient.newHttpClient();

  String getToken() throws Exception {
      String form = "grant_type=password"
          + "&client_id=ismstoken"
          + "&username=" + URLEncoder.encode(System.getenv("ISMSAPI_USERNAME"), StandardCharsets.UTF_8)
          + "&password=" + URLEncoder.encode(System.getenv("ISMSAPI_PASSWORD"), StandardCharsets.UTF_8);

      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("https://auth.interactsms.com/token"))
          .header("Content-Type", "application/x-www-form-urlencoded")
          .POST(HttpRequest.BodyPublishers.ofString(form))
          .build();

      HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
      return res.body().split("\"access_token\":\"")[1].split("\"")[0];
  }

  String apiRequest(String path) throws Exception {
      String token = getToken();
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("https://api.interactsms.com" + path))
          .header("Authorization", "Bearer " + token)
          .GET()
          .build();

      HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
      if (res.statusCode() == 401) throw new RuntimeException("Authentication failed");
      return res.body();
  }
  ```

  ```php title="PHP" icon="php" lines expandable focus={3-15,17-26} theme={"dark"}
  $client = new GuzzleHttp\Client();

  function getToken($client) {
      $res = $client->post('https://auth.interactsms.com/token', [
          'form_params' => [
              'grant_type' => 'password',
              'client_id' => 'ismstoken',
              'username' => getenv('ISMSAPI_USERNAME'),
              'password' => getenv('ISMSAPI_PASSWORD'),
          ],
      ]);

      return json_decode($res->getBody(), true)['access_token'];
  }

  function apiRequest($client, $path) {
      $token = getToken($client);
      $res = $client->get('https://api.interactsms.com' . $path, [
          'headers' => ['Authorization' => 'Bearer ' . $token],
      ]);

      return json_decode($res->getBody(), true);
  }
  ```
</CodeGroup>

<Warning>
  Never hardcode credentials in your source code. Use environment variables or a secrets manager.
</Warning>

## No sandbox environment

There is currently **no sandbox or test environment**. All API calls run against the live production system and will consume message credits. Test with a small number of your own numbers to verify your integration before going live.

## Credentials

Your username and password are available from your Phonovation account. Contact [support@phonovation.com](mailto:support@phonovation.com) if you need access.
