Renidlyrenidly
Core Concepts

Response Envelope

3 min read

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 */ }
}
FieldTypeDescription
successbooleantrue if the call succeeded, false on any failure. The one field to branch on.
statusCodenumberNumeric status carried in the body. Convenient for logs.
messagestringShort human-readable summary — safe for internal tooling, not end-user copy.
errorsobject | nullnull on success and on general failures; a per-field map on validation failures.
dataobject | array | nullThe endpoint payload. null whenever success is false.
error_code (optional)stringA stable code on some failures (e.g. 1010). See Errors.
pagination (optional)objectPresent 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.

PrefixIdentifiesExample
prsn_A personprsn_06d0d44dogo2m
org_An organizationorg_5ehe8408s7tme
inst_An institutioninst_4k8s2j9d1xph
cur_A pagination cursorcur_8kf3q2p9w1xyz

Handles & slugs

On the real-time surface you may also resolve records by their public label and reuse the returned identifier:

IdentifierSubjectNotes
handlePersonPublic profile slug. May change — prefer the id.
slugOrganizationPublic company slug. May change — prefer the id.
entityIdPerson / activityOpaque token; resolve once, then reuse.
opportunityEntityIdOpportunityOpaque token for a single posted role.