Authentication API
These endpoints sign a user in and out and manage the personal API key. Most integrations call them once: sign in, create the key, then send the key as Authorization: Bearer <key> on every other call. The concepts, including signed partner links and the CSRF rules, are in Authentication.
Every example on this page was captured from a running API. IDs, keys and tokens are replaced with samples.
Endpoints
| Method | Path | Endpoint | Auth |
|---|---|---|---|
POST | /v1/auth/login | Sign in | None |
POST | /v1/auth/login/2fa | Sign in with a 2FA code | None |
POST | /v1/auth/logout | Sign out | Session |
GET | /v1/auth/me | Get the signed-in user | Optional |
PATCH | /v1/auth/me | Update the signed-in user | Key or session |
GET | /v1/auth/me/api-key | Get the personal API key | Key or session |
POST | /v1/auth/me/api-key/rotate | Create or rotate the personal API key | Key or session |
Sign in
Signs in with email and password. On success the response sets the session cookie (__Host-rekber_session, HttpOnly, Secure) and returns csrf_token. Send that token as X-CSRF-Token on every POST, PATCH, PUT and DELETE made with the cookie.
When the account has two-step sign-in by email, the answer is { "requires_2fa": true, "method": "email", "ticket": "..." } and no cookie is set. RekberPay emails a 6-digit code; finish with POST /v1/auth/login/2fa.
- Auth: None. A successful call sets the session cookie and returns the CSRF token.
- Rate limit: Counted per IP address and email. From the third failure a Turnstile token is required, from the sixth the sign-in is locked for a while (
423 ACCOUNT_LOCKED), and after ten failures the address gets429 LOGIN_LOCKEDwithRetry-After. - Idempotency: Not supported. A retry runs the call again.
Body (JSON)
| Name | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address, at most 254 characters |
password | string | Yes | 1 to 128 characters |
turnstile_token | string | No | Cloudflare Turnstile token. Needed when Turnstile is on, and always after a few failed attempts |
Example request
curl -X POST https://api.rekberpay.com/v1/auth/login \
-c cookies.txt \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "Docs-3zv7kaA8-hp4"
}'const res = await fetch('https://api.rekberpay.com/v1/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: "[email protected]",
password: "Docs-3zv7kaA8-hp4"
}),
});
const data = await res.json();
// Keep the session cookie and the CSRF token for later calls.
const cookie = res.headers.get('set-cookie').split(';')[0];
const csrfToken = data.data.csrf_token;import os
import requests
session = requests.Session()
resp = session.post(
"https://api.rekberpay.com/v1/auth/login",
json={
"email": "[email protected]",
"password": "Docs-3zv7kaA8-hp4",
},
timeout=30,
)
print(resp.status_code, resp.json())
csrf_token = resp.json()["data"]["csrf_token"]<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/login');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'password' => 'Docs-3zv7kaA8-hp4',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true,
"data": {
"user": {
"id": "11111110-1111-4111-8111-111111111111",
"email": "[email protected]",
"role": "user",
"full_name": "Rina Wijaya",
"username": "rinadocs",
"phone": null,
"kyc_status": "verified",
"balance": 0,
"is_suspended": false,
"is_verified": false,
"two_factor_method": "none",
"dashboard_tour_completed_at": null,
"social_instagram": null,
"social_shopee": null,
"social_tiktokshop": null,
"created_at": "2026-10-13T14:18:52.168Z",
"has_password": true,
"email_verification_required": false
},
"csrf_token": "Gq7Lm2Vx9Rt4Kp1Ns8Bw3Hz6Yc0Df5J"
}
}| Field | Type | Description |
|---|---|---|
user | object | The signed-in user. Same shape as GET /v1/auth/me |
csrf_token | string | Send it as X-CSRF-Token on writes made with this session |
Errors
| Status | Code | Cause |
|---|---|---|
400 | INVALID_BODY | Email or password missing or too long |
400 | TURNSTILE_REQUIRED | A few attempts failed, so a Turnstile token is now required. The error has requires_captcha: true |
400 | TURNSTILE_FAILED | The Turnstile token did not verify |
401 | INVALID_CREDENTIALS | Wrong email or password. The same answer is given for an unknown email |
403 | ACCOUNT_INACTIVE, SUSPENDED | Correct password, but the account is closed or suspended |
423 | ACCOUNT_LOCKED | Too many failed attempts. Try again later |
429 | LOGIN_LOCKED | Too many failures from this address. Wait for Retry-After seconds |
501 | TWO_FACTOR_METHOD_UNSUPPORTED | The account uses a second factor that sign-in does not support yet |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
A real INVALID_CREDENTIALS answer:
401 Unauthorized
{
"success": false,
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Invalid credentials.",
"requires_captcha": false
}
}Sign in with a 2FA code
Completes a sign-in that answered requires_2fa: true. Send the ticket from that answer and the 6-digit code from the email. A correct code gives the same answer as a normal sign-in: the session cookie plus user and csrf_token.
The example shows a real answer to an expired ticket. A successful answer has the same shape as Sign in.
- Auth: None. A successful call sets the session cookie and returns the CSRF token.
- Rate limit: Counted per IP address and email. From the third failure a Turnstile token is required, from the sixth the sign-in is locked for a while (
423 ACCOUNT_LOCKED), and after ten failures the address gets429 LOGIN_LOCKEDwithRetry-After. - Idempotency: Not supported. A retry runs the call again.
Body (JSON)
| Name | Type | Required | Description |
|---|---|---|---|
ticket | string | Yes | The ticket from the sign-in answer |
code | string | Yes | Exactly 6 digits |
Example request
curl -X POST https://api.rekberpay.com/v1/auth/login/2fa \
-H "Content-Type: application/json" \
-d '{
"ticket": "eyJ0eXAiOiIyZmFfbG9naW4iLCJzdWIiOiIuLi4ifQ.sample",
"code": "123456"
}'const res = await fetch('https://api.rekberpay.com/v1/auth/login/2fa', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
ticket: "eyJ0eXAiOiIyZmFfbG9naW4iLCJzdWIiOiIuLi4ifQ.sample",
code: "123456"
}),
});
const data = await res.json();import os
import requests
resp = requests.post(
"https://api.rekberpay.com/v1/auth/login/2fa",
json={
"ticket": "eyJ0eXAiOiIyZmFfbG9naW4iLCJzdWIiOiIuLi4ifQ.sample",
"code": "123456",
},
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/login/2fa');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'ticket' => 'eyJ0eXAiOiIyZmFfbG9naW4iLCJzdWIiOiIuLi4ifQ.sample',
'code' => '123456',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
401 Unauthorized
{
"success": false,
"error": {
"code": "INVALID_TICKET",
"message": "Sesi login telah kadaluarsa. Silakan login kembali."
}
}Errors
| Status | Code | Cause |
|---|---|---|
400 | INVALID_BODY | Ticket missing or the code is not 6 digits |
401 | INVALID_TICKET | The ticket expired or is unknown. Sign in again |
401 | INVALID_CODE | Wrong or expired code. error.reason is wrong, expired or exhausted |
403 | ACCOUNT_INACTIVE, SUSPENDED | The account is closed or suspended |
423 | ACCOUNT_LOCKED | Too many wrong codes. Try again later |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
Sign out
Ends the session and clears the cookie. With an API key the call succeeds and changes nothing.
- Auth: A session cookie. Writes also need
X-CSRF-Token. - Rate limit: 300 requests a minute per user, shared by every route.
- Idempotency: Not supported. A retry runs the call again.
Example request
curl -X POST https://api.rekberpay.com/v1/auth/logout \
-b cookies.txt \
-H "X-CSRF-Token: $CSRF_TOKEN"const res = await fetch('https://api.rekberpay.com/v1/auth/logout', {
method: 'POST',
headers: {
Cookie: process.env.REKBERPAY_SESSION_COOKIE, // '__Host-rekber_session=...' from POST /v1/auth/login
'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
},
});
const data = await res.json();import os
import requests
session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
"https://api.rekberpay.com/v1/auth/logout",
headers={
"X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
},
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/logout');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_HTTPHEADER => [
'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
],
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true
}Errors
| Status | Code | Cause |
|---|---|---|
401 | UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKEN | No session or API key, the session expired, or the key is wrong or revoked |
401 | WORKSPACE_KEY_ONLY | A workspace key (rpe_...) was sent. Those only work under /v1/enterprise |
403 | CSRF_FAILED | Session call without the matching X-CSRF-Token header |
403 | ACCOUNT_INACTIVE, SUSPENDED | The account is closed, being deleted or suspended |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
Get the signed-in user
Returns the user behind the session or API key, plus the session's csrf_token (null for API keys). Signed out, it answers 200 with "data": null instead of an error, so it is safe to call on page load.
- Auth: Optional. It works signed out; with a session or API key it also tells you whether you are a party.
- Rate limit: 300 requests a minute per user, shared by every route.
- Idempotency: Not needed. Reading has no side effects.
Example request
curl https://api.rekberpay.com/v1/auth/me \
-b cookies.txtconst res = await fetch('https://api.rekberpay.com/v1/auth/me', {
headers: {
Cookie: process.env.REKBERPAY_SESSION_COOKIE, // '__Host-rekber_session=...' from POST /v1/auth/login
},
});
const data = await res.json();import os
import requests
session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.get(
"https://api.rekberpay.com/v1/auth/me",
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/me');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true,
"data": {
"user": {
"id": "11111110-1111-4111-8111-111111111111",
"email": "[email protected]",
"role": "user",
"full_name": "Rina Wijaya",
"username": "rinadocs",
"phone": null,
"kyc_status": "verified",
"balance": 0,
"is_suspended": false,
"is_verified": false,
"two_factor_method": "none",
"dashboard_tour_completed_at": null,
"social_instagram": null,
"social_shopee": null,
"social_tiktokshop": null,
"created_at": "2026-10-13T14:18:52.168Z",
"has_password": true,
"email_verification_required": false
},
"csrf_token": "Gq7Lm2Vx9Rt4Kp1Ns8Bw3Hz6Yc0Df5J"
}
}| Field | Type | Description |
|---|---|---|
user.id | UUID | User ID. This is the seller or buyer value in signed links |
user.role | string | user for normal accounts |
user.kyc_status | string | none, pending, verified or rejected |
user.balance | number | RekberPay balance in rupiah |
user.two_factor_method | string | none or email |
user.email_verification_required | boolean | true while an account that signed up with email and password has not confirmed its email. Escrow, payment and withdrawal writes answer 403 EMAIL_NOT_VERIFIED until then |
csrf_token | string | null | The session token for X-CSRF-Token. null with an API key |
Errors
| Status | Code | Cause |
|---|---|---|
404 | USER_NOT_FOUND | The account was removed while the session was open |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
Update the signed-in user
Changes profile fields. Send only the fields you want to change. Unknown fields are rejected.
- Auth: A personal API key (
Authorization: Bearer <key>) or a session cookie withX-CSRF-Tokenon writes. - Rate limit: 300 requests a minute per user, shared by every route.
- Idempotency: Not supported. A retry runs the call again.
Body (JSON)
| Name | Type | Required | Description |
|---|---|---|---|
full_name | string | No | At most 120 characters, no <, > or ". An empty string clears it |
username | string | No | 3 to 30 characters: lowercase letters, digits, _ and .. Must be unique |
phone | string | No | At most 32 characters |
social_instagram | string | No | Instagram handle or profile URL |
social_shopee | string | No | Shopee shop URL |
social_tiktokshop | string | No | TikTok Shop URL |
Example request
curl -X PATCH https://api.rekberpay.com/v1/auth/me \
-b cookies.txt \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "rina.wijaya",
"phone": "081234567890"
}'const res = await fetch('https://api.rekberpay.com/v1/auth/me', {
method: 'PATCH',
headers: {
Cookie: process.env.REKBERPAY_SESSION_COOKIE, // '__Host-rekber_session=...' from POST /v1/auth/login
'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: "rina.wijaya",
phone: "081234567890"
}),
});
const data = await res.json();import os
import requests
session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.patch(
"https://api.rekberpay.com/v1/auth/me",
headers={
"X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
},
json={
"username": "rina.wijaya",
"phone": "081234567890",
},
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/me');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_HTTPHEADER => [
'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'username' => 'rina.wijaya',
'phone' => '081234567890',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true,
"data": {
"user": {
"id": "11111110-1111-4111-8111-111111111111",
"email": "[email protected]",
"role": "user",
"full_name": "Rina Wijaya",
"username": "rina.wijaya",
"phone": "081234567890",
"kyc_status": "verified",
"balance": 0,
"is_suspended": false,
"is_verified": false,
"two_factor_method": "none",
"dashboard_tour_completed_at": null,
"social_instagram": null,
"social_shopee": null,
"social_tiktokshop": null,
"created_at": "2026-10-13T14:18:52.168Z",
"has_password": true,
"email_verification_required": false
}
}
}Errors
| Status | Code | Cause |
|---|---|---|
400 | INVALID_BODY | An unknown field, or a field that is too long |
400 | NO_UPDATES | The body had no fields |
400 | INVALID_USERNAME, INVALID_FULL_NAME | The value has characters that are not allowed |
400 | INVALID_SOCIAL_INSTAGRAM, INVALID_SOCIAL_SHOPEE, INVALID_SOCIAL_TIKTOKSHOP | The handle or URL is not valid for that site |
409 | USERNAME_TAKEN | Another user has this username |
401 | UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKEN | No session or API key, the session expired, or the key is wrong or revoked |
401 | WORKSPACE_KEY_ONLY | A workspace key (rpe_...) was sent. Those only work under /v1/enterprise |
403 | CSRF_FAILED | Session call without the matching X-CSRF-Token header |
403 | ACCOUNT_INACTIVE, SUSPENDED | The account is closed, being deleted or suspended |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
Get the personal API key
Shows a masked preview of your live personal API key, when it was created and when it was last used. Every field is null when the account has no live key (none was ever created, or the last one was revoked). The full key is only shown once, when it is created. Check last_used_at before you rotate: a recent time means something still uses the key.
- Auth: A personal API key (
Authorization: Bearer <key>) or a session cookie withX-CSRF-Tokenon writes. - Rate limit: 300 requests a minute per user, shared by every route.
- Idempotency: Not needed. Reading has no side effects.
Example request
curl https://api.rekberpay.com/v1/auth/me/api-key \
-b cookies.txtconst res = await fetch('https://api.rekberpay.com/v1/auth/me/api-key', {
headers: {
Cookie: process.env.REKBERPAY_SESSION_COOKIE, // '__Host-rekber_session=...' from POST /v1/auth/login
},
});
const data = await res.json();import os
import requests
session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.get(
"https://api.rekberpay.com/v1/auth/me/api-key",
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/me/api-key');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true,
"data": {
"api_key": "rpk_kM•••••••••••••••••••••••••••••••••••••tN6r",
"created_at": "2026-10-18T03:04:05.000Z",
"last_used_at": "2026-10-18T09:12:44.000Z"
}
}| Field | Type | Description |
|---|---|---|
api_key | string | null | Masked preview of the live key: its first 6 and last 4 characters. null when there is no live key |
created_at | string | null | When the live key was created (ISO 8601, UTC) |
last_used_at | string | null | When the live key last authenticated a request (ISO 8601, UTC, updated at most once a minute). null when it was never used |
Errors
| Status | Code | Cause |
|---|---|---|
401 | UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKEN | No session or API key, the session expired, or the key is wrong or revoked |
401 | WORKSPACE_KEY_ONLY | A workspace key (rpe_...) was sent. Those only work under /v1/enterprise |
403 | ACCOUNT_INACTIVE, SUSPENDED | The account is closed, being deleted or suspended |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |
Create or rotate the personal API key
Creates a new personal API key and revokes every older one at once. The answer holds the plaintext key. Store it now: only a hash is kept, so it cannot be shown again.
- New keys start with
rpk_. Older keys without the prefix keep working until you rotate them. - At most 5 rotations per account per hour. The sixth gets
429 ROTATE_LIMITEDand the current key stays as it is. - Every rotation emails the account owner, with the time and IP address. The email never contains the key.
- Signing in on the RekberPay phone apps no longer changes the key. Only this call (the Generate Baru button in the dashboard) does.
The key acts as you on every route outside /v1/enterprise and is not subject to CSRF. A password reset or a password change revokes every personal API key of the account, so create a new key afterwards. A key never carries staff rights: RekberPay admin routes only accept a signed-in session. For server-to-server work on a business workspace, use a workspace API key instead.
- Auth: A personal API key (
Authorization: Bearer <key>) or a session cookie withX-CSRF-Tokenon writes. - Rate limit: 300 requests a minute per user, shared by every route.
- Idempotency: Not supported. A retry runs the call again.
Body (JSON)
| Name | Type | Required | Description |
|---|---|---|---|
label | string | No | A name for your own records, up to 64 characters: letters, digits, spaces and _ . : -, starting with a letter or digit. Defaults to default |
Example request
curl -X POST https://api.rekberpay.com/v1/auth/me/api-key/rotate \
-b cookies.txt \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "docs"
}'const res = await fetch('https://api.rekberpay.com/v1/auth/me/api-key/rotate', {
method: 'POST',
headers: {
Cookie: process.env.REKBERPAY_SESSION_COOKIE, // '__Host-rekber_session=...' from POST /v1/auth/login
'X-CSRF-Token': process.env.REKBERPAY_CSRF_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
label: "docs"
}),
});
const data = await res.json();import os
import requests
session = requests.Session()
# The session cookie from POST /v1/auth/login
session.cookies.set("__Host-rekber_session", os.environ["REKBERPAY_SESSION"], domain="api.rekberpay.com")
resp = session.post(
"https://api.rekberpay.com/v1/auth/me/api-key/rotate",
headers={
"X-CSRF-Token": os.environ["REKBERPAY_CSRF_TOKEN"],
},
json={
"label": "docs",
},
timeout=30,
)
print(resp.status_code, resp.json())<?php
$ch = curl_init('https://api.rekberpay.com/v1/auth/me/api-key/rotate');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_HTTPHEADER => [
'X-CSRF-Token: ' . getenv('REKBERPAY_CSRF_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'label' => 'docs',
]),
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);Example response
200 OK
{
"success": true,
"data": {
"api_key": "rpk_kM3vT8qR1xZ6nB4wY9pL2sD7fH0jC5gA3eU8iO1tN6r"
}
}Errors
| Status | Code | Cause |
|---|---|---|
400 | INVALID_BODY | The body is not a JSON object, or label is not a string, is empty or longer than 64 characters, does not start with a letter or digit, or has other characters |
401 | UNAUTHORIZED, SESSION_EXPIRED, INVALID_TOKEN | No session or API key, the session expired, or the key is wrong or revoked |
401 | WORKSPACE_KEY_ONLY | A workspace key (rpe_...) was sent. Those only work under /v1/enterprise |
403 | CSRF_FAILED | Session call without the matching X-CSRF-Token header |
403 | ACCOUNT_INACTIVE, SUSPENDED | The account is closed, being deleted or suspended |
429 | ROTATE_LIMITED | More than 5 rotations in the last hour. The key was not changed. Try again after Retry-After seconds |
429 | RATE_LIMITED | Over the rate limit. Wait for Retry-After seconds |