What we will call
We will useGET /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 or Authentication page if you have not generated one.
- A terminal with
curlavailable, 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.
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:| 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
TheAuthorization header has a precise shape:
- The word
Authorizationis the header name. Some HTTP libraries normalize header casing automatically; if yours does not, use this exact spelling. - The word
Beareris 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.
Bearer "abc123" or Bearer abc123 (two spaces) will both return 401.
Make the call
-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.Status code
A200 OK confirms the request was authenticated, authorized, and processed successfully. The full list of status codes you may encounter is on the 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. |
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. |
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.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:
- Did you include the
Authorizationheader? Runcurl -vto confirm the header is being sent. - Is the header value exactly
Bearer YOUR_API_TOKENwith one space betweenBearerand 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_invalue returned at issuance. Use the refresh token to obtain a new one — see Authentication.
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(notwww.virtuoussoftware.comorapp.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 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 returns200, 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:Error Handling
Full coverage of status codes, the error envelope shape, and defensive client patterns.
Rate Limits
How the 5,000-per-hour limit works and how to handle 429 with exponential backoff.
Pagination and Filtering
Iterate large result sets safely using
skip and take.Virtuous CRM Data Model
The Contact, Gift, and Designation hierarchy every integration depends on.
Create a Contact
Your first write workflow — and why most partners should use the transaction endpoint.
Sync External Donations
The canonical recipe for pushing Gifts from your platform into Virtuous.