curl --request POST \
--url https://api.reply.io/v3/api-keys \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "user",
"name": "Outbound agent",
"scopes": [
"contacts:read",
"inbox:operate"
],
"expiresAt": "2026-12-20T09:00:00Z"
}
'import requests
url = "https://api.reply.io/v3/api-keys"
payload = {
"type": "user",
"name": "Outbound agent",
"scopes": ["contacts:read", "inbox:operate"],
"expiresAt": "2026-12-20T09:00:00Z"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
type: 'user',
name: 'Outbound agent',
scopes: ['contacts:read', 'inbox:operate'],
expiresAt: '2026-12-20T09:00:00Z'
})
};
fetch('https://api.reply.io/v3/api-keys', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.reply.io/v3/api-keys",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'type' => 'user',
'name' => 'Outbound agent',
'scopes' => [
'contacts:read',
'inbox:operate'
],
'expiresAt' => '2026-12-20T09:00:00Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.reply.io/v3/api-keys"
payload := strings.NewReader("{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.reply.io/v3/api-keys")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/api-keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}"
response = http.request(request)
puts response.read_body{
"id": 8120,
"type": "user",
"name": "Outbound agent",
"hint": "usk_Zm9y...1rZXk",
"scopes": [
"contacts:read",
"inbox:operate"
],
"createdAt": "2026-11-20T09:00:00Z",
"expiresAt": "2026-12-20T09:00:00Z",
"key": "usk_Zm9yLWRvY3Mtb25seS1ub3QtYS1rZXk"
}Create an API key
Coming soon. This endpoint will be available by mid November 2026.
api-keys:write scope (or a broader one that includes it).
Create a key as Settings → API Key does. key appears in this response only.
An API key needs api-keys:write, which *:* does not include, and may create only keys no wider than itself; only an organization key may create an organization key. A session token of an application other than Reply’s own is refused from creating or widening keys. This bounds registered applications; it is not a credential check, since a public application’s identifier is not a secret.
type defaults to user; team needs the team owner, organization the right to manage organization keys. scopes takes exact values; wildcards are granted only in Settings. An API key with an expiry must set expiresAt, no later than its own. An owner holds at most 25 unexpired keys of a type.
curl --request POST \
--url https://api.reply.io/v3/api-keys \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "user",
"name": "Outbound agent",
"scopes": [
"contacts:read",
"inbox:operate"
],
"expiresAt": "2026-12-20T09:00:00Z"
}
'import requests
url = "https://api.reply.io/v3/api-keys"
payload = {
"type": "user",
"name": "Outbound agent",
"scopes": ["contacts:read", "inbox:operate"],
"expiresAt": "2026-12-20T09:00:00Z"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
type: 'user',
name: 'Outbound agent',
scopes: ['contacts:read', 'inbox:operate'],
expiresAt: '2026-12-20T09:00:00Z'
})
};
fetch('https://api.reply.io/v3/api-keys', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.reply.io/v3/api-keys",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'type' => 'user',
'name' => 'Outbound agent',
'scopes' => [
'contacts:read',
'inbox:operate'
],
'expiresAt' => '2026-12-20T09:00:00Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.reply.io/v3/api-keys"
payload := strings.NewReader("{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.reply.io/v3/api-keys")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reply.io/v3/api-keys")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"type\": \"user\",\n \"name\": \"Outbound agent\",\n \"scopes\": [\n \"contacts:read\",\n \"inbox:operate\"\n ],\n \"expiresAt\": \"2026-12-20T09:00:00Z\"\n}"
response = http.request(request)
puts response.read_body{
"id": 8120,
"type": "user",
"name": "Outbound agent",
"hint": "usk_Zm9y...1rZXk",
"scopes": [
"contacts:read",
"inbox:operate"
],
"createdAt": "2026-11-20T09:00:00Z",
"expiresAt": "2026-12-20T09:00:00Z",
"key": "usk_Zm9yLWRvY3Mtb25seS1ub3QtYS1rZXk"
}Authorizations
Authenticate every request with a Bearer token. Pass your Reply API key in the
Authorization header:
Authorization: Bearer <your-api-key>
Get your API key from the Reply dashboard: Settings → API Key.
Body
Who the key belongs to.
user, team, organization A name to tell the key apart.
100Exact scope values, such as contacts:read.
When the key stops working, which cannot change later. It must be in the future; leave it out and the key never expires. An API key that has an expiry must set this, no later than its own.
Response
The key was created.
The key's id.
Who the key belongs to.
user, team, organization The start and end of the key, as Settings shows it.
When the key was created.
The scopes as stored, which may include wildcards set in Settings.
The API key. It appears in this response only.
The key's name.
When the key stops working, or null if it never does.