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

# Make Your First API Call

> A detailed walkthrough of one CRM+ API request — the URL, headers, response, and how to debug common first-call failures.

This page walks through one CRM+ request in detail — every header, every byte of the response, and the failure modes you are most likely to hit on a first integration attempt. The goal is to make every component of an HTTP call to Virtuous obvious so you can debug confidently when something does not work.

If you only need to copy a working snippet and move on, the [Quickstart](/crm/quickstart) is shorter and more action-oriented.

## What we will call

We will use `GET /api/Organization/Current` — the simplest authenticated CRM+ endpoint. It takes no path parameters, no query parameters, no request body, and returns a single object describing the organization the credential belongs to. Its only job is to confirm that authentication is working and that the credential resolves to the expected Virtuous organization.

## Prerequisites

* A valid CRM+ API Key — see the [Quickstart](/crm/quickstart) or [Authentication](/crm/authentication) page if you have not generated one.
* A terminal with `curl` available, or a Node.js environment if you prefer JavaScript.
* The API Key available as an environment variable, secrets manager entry, or otherwise outside of source control.

<Warning>
  Do not paste your API Key into a public terminal session, a shared notebook, or any chat tool. Set it as an environment variable (`export VIRTUOUS_API_TOKEN="..."`) for the duration of testing and reference it from there.
</Warning>

***

## Anatomy of the request

Every CRM+ API request has four components: the **method**, the **URL**, the **headers**, and (for write operations) a **body**. The call we are making uses three of them:

```http theme={null}
GET /api/Organization/Current HTTP/1.1
Host: api.virtuoussoftware.com
Authorization: Bearer YOUR_API_TOKEN
```

| Component              | Value                                                       | Why it matters                                                                                                                           |
| ---------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Method                 | `GET`                                                       | Reads data. Safe to retry. Never modifies records.                                                                                       |
| URL                    | `https://api.virtuoussoftware.com/api/Organization/Current` | Base URL (`https://api.virtuoussoftware.com`) plus the endpoint path (`/api/Organization/Current`).                                      |
| `Authorization` header | `Bearer YOUR_API_TOKEN`                                     | Identifies and authorizes the caller. Required on every request.                                                                         |
| `Content-Type` header  | Omitted on `GET`                                            | `GET` requests have no body, so the header is optional. Include `Content-Type: application/json` on `POST`, `PUT`, and `PATCH` requests. |

### The Authorization header in detail

The `Authorization` header has a precise shape:

```text theme={null}
Authorization: Bearer YOUR_API_TOKEN
```

Three things to get right:

* The word `Authorization` is the header name. Some HTTP libraries normalize header casing automatically; if yours does not, use this exact spelling.
* The word `Bearer` is the auth scheme, followed by a single space.
* The token comes immediately after `Bearer `. Do not include quotes around it, do not include `=` or `:`, and do not URL-encode it.

A common mistake when copy-pasting from secrets managers is to include surrounding whitespace or quotes inside the value — `Bearer "abc123"` or `Bearer  abc123` (two spaces) will both return `401`.

***

## Make the call

<CodeGroup>
  ```bash cURL theme={null}
  curl -i https://api.virtuoussoftware.com/api/Organization/Current \
    -H "Authorization: Bearer $VIRTUOUS_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.virtuoussoftware.com/api/Organization/Current',
    {
      headers: {
        Authorization: `Bearer ${process.env.VIRTUOUS_API_TOKEN}`,
      },
    }
  );

  console.log('Status:', response.status);
  console.log('Rate limit remaining:', response.headers.get('X-RateLimit-Remaining'));

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`Request failed (${response.status}): ${body}`);
  }

  const org = await response.json();
  console.log(org);
  ```
</CodeGroup>

The `-i` flag on `curl` prints the response headers along with the body — useful for seeing the rate-limit headers and the exact status code on the first call.

***

## Anatomy of the response

A successful response has three components: the **status code**, the **headers**, and the **body**.

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 1499
X-RateLimit-Reset: 1713914400

{
  "organizationUserId": 67890,
  "organizationName": "The Human Fund",
  "organizationTimeZone": "US/Arizona",
  "organizationCulture": "en-US",
  "currentUserTimeZone": "US/Arizona",
  "isAdministrator": true,
  "isEnabled": true
}
```

### Status code

A `200 OK` confirms the request was authenticated, authorized, and processed successfully. The full list of status codes you may encounter is on the [Error Handling](/crm/error-handling) page.

### Headers worth inspecting

| Header                  | Meaning                                                                                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `Content-Type`          | Always `application/json` on successful responses. Treat anything else as a transport-level error and do not attempt to parse the body as JSON. |
| `X-RateLimit-Limit`     | Total request limit for the current window. Always `5000`.                                                                                      |
| `X-RateLimit-Remaining` | Requests remaining in the current window. Read this on every response.                                                                          |
| `X-RateLimit-Reset`     | Unix timestamp (in seconds) when the rate-limit window resets.                                                                                  |

See [Rate Limits](/rate-limits) for how to use these headers in production integrations.

### Body fields

The body is a single JSON object describing the organization the credential belongs to:

| Field                  | Type      | Meaning                                                                                                                                                          |
| ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationUserId`   | `integer` | The unique identifier for the (user, organization) pair this credential authenticates as.                                                                        |
| `organizationName`     | `string`  | The human-readable name of the Virtuous organization.                                                                                                            |
| `organizationTimeZone` | `string`  | The organization's configured time zone. Date and time fields elsewhere in the API are interpreted in this zone.                                                 |
| `organizationCulture`  | `string`  | The organization's locale (e.g., `en-US`).                                                                                                                       |
| `currentUserTimeZone`  | `string`  | The current user's personal time zone preference.                                                                                                                |
| `isAdministrator`      | `boolean` | Whether the authenticated user has administrator privileges in this organization.                                                                                |
| `isEnabled`            | `boolean` | Whether the organization is currently enabled in Virtuous. A `false` value indicates the organization is administratively disabled and most API calls will fail. |

<Check>
  If your response has `200 OK`, a JSON body, and the organization name matches the Virtuous account you generated the API Key in, your integration is correctly configured to talk to Virtuous. You are ready to make read and write calls against the rest of the API.
</Check>

***

## Common first-call failures

Most first-call failures fall into one of four categories. Each one is fixable in under a minute once you know what to look for.

### `401 Unauthorized`

The credential is missing, malformed, or rejected. Inspect the response body — many `401` responses return a plain-text message rather than JSON:

```text theme={null}
Authorization has been denied for this request.
```

Walk through the checklist:

* Did you include the `Authorization` header? Run `curl -v` to confirm the header is being sent.
* Is the header value exactly `Bearer YOUR_API_TOKEN` with one space between `Bearer` and the token? No quotes, no trailing whitespace, no extra characters.
* Is the token currently active in **Settings → Integrations → API Keys**? A key can be revoked at any time.
* For OAuth tokens: has the access token expired? OAuth access tokens expire after the `expires_in` value returned at issuance. Use the refresh token to obtain a new one — see [Authentication](/crm/authentication#refresh-an-oauth-token).

### `403 Forbidden`

The credential is valid, but the permission group attached to it does not grant access to this resource. `GET /api/Organization/Current` requires only basic authenticated access, so a `403` here typically means the API Key was created in a permission group with extremely restrictive settings. Open the key in the Virtuous UI and confirm the permission group includes basic read access.

### `404 Not Found`

The URL is wrong. Confirm:

* The base URL is `https://api.virtuoussoftware.com` (not `www.virtuoussoftware.com` or `app.virtuoussoftware.com`).
* The path begins with `/api/` and matches the casing in the reference documentation.
* For endpoints with path parameters, the parameter is actually substituted into the URL — `/api/Contact/{contactId}` is the documented form; the real call uses `/api/Contact/4821`.

### `429 Too Many Requests`

The rate limit is exceeded. Wait for the period indicated in the `Retry-After` response header before retrying. See [Rate Limits](/crm/rate-limits) for the full retry-with-backoff pattern.

***

## Debugging tools

When a call is not behaving the way the documentation suggests, these tools usually find the problem quickly:

* **`curl -v`** — prints the full request and response, including all headers. Confirms what is actually being sent on the wire.
* **A logging proxy** — point your integration's HTTP client at a local proxy (mitmproxy, Charles Proxy, Proxyman) to see exactly what your client library is generating. Often the bug is a header your library is silently dropping or adding.
* **`GET /api/Organization/Current`** — the request on this page is the canonical "is the credential working" check. If this call returns `200`, the credential is fine and the problem is on the specific endpoint you were originally calling.
* **The HTTP response body, always** — even on errors. The CRM+ API returns helpful error messages in most cases. Read them before reaching out to support.

***

## Where to go from here

You have made a successful authenticated call, inspected the response, and seen the failure modes. The next pages cover the patterns every partner integration needs:

<CardGroup cols={2}>
  <Card title="Error Handling" icon="circle-exclamation" href="/crm/error-handling">
    Full coverage of status codes, the error envelope shape, and defensive client patterns.
  </Card>

  <Card title="Rate Limits" icon="gauge" href="/crm/rate-limits">
    How the 5,000-per-hour limit works and how to handle 429 with exponential backoff.
  </Card>

  <Card title="Pagination and Filtering" icon="list" href="/crm/pagination">
    Iterate large result sets safely using `skip` and `take`.
  </Card>

  <Card title="Virtuous CRM Data Model" icon="diagram-project" href="/crm/concepts/data-model">
    The Contact, Gift, and Designation hierarchy every integration depends on.
  </Card>

  <Card title="Create a Contact" icon="user-plus" href="/crm/workflows/create-a-contact">
    Your first write workflow — and why most partners should use the transaction endpoint.
  </Card>

  <Card title="Sync External Donations" icon="arrow-right-arrow-left" href="/crm/workflows/sync-external-donations">
    The canonical recipe for pushing Gifts from your platform into Virtuous.
  </Card>
</CardGroup>
