Response Envelope
Every Renidly endpoint — successful or not — wraps its result in the same JSON envelope. Learn it once and every endpoint feels familiar from the first call.
The shape
{
"success": true,
"statusCode": 200,
"message": "Data retrieved successfully",
"errors": null,
"data": { /* endpoint-specific payload */ }
}| Field | Type | Description |
|---|---|---|
| success | boolean | true if the call succeeded, false on any failure. The one field to branch on. |
| statusCode | number | Numeric status carried in the body. Convenient for logs. |
| message | string | Short human-readable summary — safe for internal tooling, not end-user copy. |
| errors | object | null | null on success and on general failures; a per-field map on validation failures. |
| data | object | array | null | The endpoint payload. null whenever success is false. |
error_code (optional) | string | A stable code on some failures (e.g. 1010). See Errors. |
pagination (optional) | object | Present on list endpoints. See Pagination. |
On failure
A failed call keeps the same envelope. data becomes null, message carries the reason, and errors is either null (general failure) or a per-field map (validation failure).
General failure — errors is null
For anything not tied to a specific input field — a record that doesn't exist, a missing required parameter, an auth or billing problem — the reason is in message, often alongside a stable error_code:
{
"success": false,
"statusCode": 404,
"message": "Profile not found",
"error_code": "1010",
"errors": null,
"data": null
}Validation failure — errors is a field map
When one or more inputs fail validation, message is a fixed line and errors is a { field: reason } map naming each offending field:
{
"success": false,
"statusCode": 400,
"message": "validation error; Please recheck your inputs",
"errors": {
"handle": "handle is required"
},
"data": null
}One helper, every endpoint
Because the envelope is consistent, wrap fetch once and never repeat envelope handling:
// One helper, every endpoint. Branch on body.success — not on the HTTP status.
type Envelope<T> = {
success: boolean;
statusCode: number;
message: string;
error_code?: string; // present on some failures (stable code)
errors: Record<string, string> | null; // null for general failures, map for validation
data: T | null;
};
export async function renidly<T>(path: string, init: RequestInit = {}): Promise<T> {
const res = await fetch("https://renidly.com" + path, {
...init,
headers: {
"X-renidly-apikey": process.env.RENIDLY_API_KEY!,
...(init.headers || {}),
},
});
const body = (await res.json()) as Envelope<T>;
if (!body.success || body.data === null) {
// Validation failures name the offending fields in body.errors. Everything
// else (auth, business rules, missing params) explains itself in body.message.
const detail = body.errors
? Object.entries(body.errors).map(([k, v]) => k + ": " + v).join("; ")
: body.message;
throw new RenidlyError(body.message, detail, body.error_code, body.errors);
}
return body.data;
}Identifiers you'll see in data
Records are addressed by stable identifiers. Prefer an id over a handle or slug wherever you can: a handle or slug is a human-readable label that the owner can change, while an id is permanent. Every record returns its id, so store that.
Opaque prefixed ids
Across the structured dataset, every id is an opaque, prefixed token. The prefix tells you the object type; the token carries no internal meaning, can't be guessed or enumerated, and is safe to store. Pass it straight back to fetch the record by id.
| Prefix | Identifies | Example |
|---|---|---|
prsn_ | A person | prsn_06d0d44dogo2m |
org_ | An organization | org_5ehe8408s7tme |
inst_ | An institution | inst_4k8s2j9d1xph |
cur_ | A pagination cursor | cur_8kf3q2p9w1xyz |
Handles & slugs
On the real-time surface you may also resolve records by their public label and reuse the returned identifier:
| Identifier | Subject | Notes |
|---|---|---|
handle | Person | Public profile slug. May change — prefer the id. |
slug | Organization | Public company slug. May change — prefer the id. |
entityId | Person / activity | Opaque token; resolve once, then reuse. |
opportunityEntityId | Opportunity | Opaque token for a single posted role. |