Skip to main content
Every CRM+ API request must include a valid Bearer token in the Authorization header. The API supports two token types: API Keys for server-to-server integrations, and OAuth tokens for integrations that act on behalf of a specific Virtuous user. If you have not yet generated a credential, the Quickstart walks you through creating an API Key and verifying it works.

Choose your authentication method

MethodBest forToken lifetime
API KeyPartner integrations, automated syncs, background jobs, service accounts15 years (static)
OAuth TokenUser-delegated access — your integration acts on behalf of a specific Virtuous user15 days (access token) / 365 days (refresh token)
For the majority of partner integrations, use an API Key. OAuth tokens are appropriate when your integration needs to perform actions as a specific Virtuous user — for example, an interactive admin tool where the user signs in with their own Virtuous credentials.

API Keys

Set up an API Key

1

Log into the Virtuous dashboard

Navigate to your organization’s Virtuous instance and log in with an account that has administrator permissions. Only administrators can create API Keys.
2

Open API Keys settings

Go to Settings → Integrations → API Keys.
3

Create a new key

Click Create a Key. Enter a descriptive name (typically the name of the integration you are building) and select the appropriate permission group. Click Save.
4

Copy the key immediately

After saving, the key is displayed once. Copy it and store it in a secrets manager or environment variable — the key cannot be retrieved again from the UI. If you lose it, create a replacement.
5

Use the key in requests

Pass the key as a Bearer token in the Authorization header on every request:
Authorization: Bearer YOUR_API_TOKEN
API Keys are static credentials with a 15-year lifetime. Treat them like passwords. Store them in a secrets manager or environment variable — never in source code, version control, or client-side JavaScript. If a key is compromised, revoke it from Settings → Integrations → API Keys and create a replacement.

API Keys for partner integrations

A common partner question: does each of our nonprofit customers need a separate API Key? Yes. An API Key is generated inside a specific Virtuous organization by an administrator at that organization, and it grants access only to that organization’s data. A partner integration that serves multiple nonprofit customers stores one API Key per customer and uses the correct key when calling the API on that customer’s behalf. See Base URLs and Environments for guidance on storing and routing per-tenant credentials.

OAuth Tokens

Obtain an OAuth token

OAuth tokens are issued via a POST to https://api.virtuoussoftware.com/Token using the password grant type. URL-encode the email address and password before constructing the request body to handle special characters correctly.
curl -X POST https://api.virtuoussoftware.com/Token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=YOUR_EMAIL&password=YOUR_PASSWORD"
A successful response returns the access token along with a refresh token:
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 3599,
  "refresh_token": "zyx987...",
  "userName": "developer@example.org",
  "twoFactorEnabled": "False",
  ".issued": "Thu, 10 Feb 2022 22:27:19 GMT",
  ".expires": "Sat, 25 Feb 2022 22:27:19 GMT"
}
Use the value of access_token as your Bearer token.
The expires_in value is in seconds and reflects the access token’s session window — the example above shows roughly one hour. The OAuth token’s full effective lifetime is 15 days; use the refresh token to obtain a new access token without re-prompting the user for credentials.

Refresh an OAuth token

When the access token expires, use the refresh token to obtain a new one without requiring the user to re-authenticate. Refresh tokens are valid for 365 days.
curl -X POST https://api.virtuoussoftware.com/Token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN"
Store the new access_token and refresh_token from the response — Virtuous may rotate the refresh token on each refresh, so always replace both.

Two-factor authentication

If the account has Two-Factor Authentication (2FA) enabled, the initial token request returns a 202 Accepted response indicating that a verification code is required. The user receives the code by SMS. Resubmit the request with the code added as an otp field:
cURL
curl -X POST https://api.virtuoussoftware.com/Token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=YOUR_EMAIL&password=YOUR_PASSWORD&otp=YOUR_OTP"
A successful response after OTP submission returns the standard token payload.

Making an authenticated request

Pass your token in the Authorization header on every API request. The header format is identical for API Keys and OAuth tokens.
curl https://api.virtuoussoftware.com/api/Contact/4821 \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json"
For a longer walkthrough — request anatomy, response inspection, and debugging — see Make Your First API Call.

Authentication errors

ScenarioStatusWhat it means
Missing Authorization header401No credentials were provided on the request.
Invalid or expired token401The token is malformed, has been revoked in the Virtuous UI, or — for OAuth — has expired.
Valid token, insufficient permissions403The credential is valid but the permission group attached to it does not grant access to this resource or action.
The CRM+ API does not currently return a structured JSON error body for all 401 responses — some endpoints return a plain-text Authorization has been denied for this request. message. The target canonical error shape is documented on the Error Handling page. Handle 401 defensively by checking response.status first; do not assume the body is always JSON.
If you receive a 403, the most common cause is that the API Key’s permission group does not include the resource you are calling. Confirm the permission group assignment in Settings → Integrations → API Keys and adjust if needed.

HMAC-authenticated endpoints

A small number of CRM+ endpoints require HMAC authentication instead of Bearer token authentication. The most notable is GET /api/Contact/ByReference/{referenceId}, which is used to look up Contacts by an external reference identifier. HMAC auth uses a different credential and signing mechanism from the standard API Key. If you receive a 401 on an endpoint marked as “HMAC Auth only,” contact Virtuous support to obtain HMAC credentials and signing instructions.
The CRM+ spec flags HMAC-restricted endpoints with only the note “HMAC Auth only” — no inline explanation of how to obtain or use HMAC credentials. Until this documentation gap is addressed, contact Virtuous support before relying on HMAC-only endpoints in your integration.

Security recommendations for partner integrations

  • Use a secrets manager. Store every customer’s API Key in a managed secrets service (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Doppler, 1Password, etc.) — never in your application database in plaintext.
  • Scope per customer. Use a separate API Key for each nonprofit customer. Do not pool credentials across customers.
  • Rotate on compromise. If an API Key is exposed in logs, source control, or a third-party system, treat it as compromised. Revoke it in the Virtuous UI and generate a replacement immediately.
  • Audit your dependency chain. If your integration calls third-party services with the Virtuous-derived data, confirm those services do not log or store the API Key inadvertently.
  • Prefer API Keys over OAuth for service accounts. OAuth tokens are tied to a specific Virtuous user; if that user leaves the nonprofit, the OAuth credentials are revoked. API Keys are independent of any single user and survive personnel changes.

Cross-API note

The Raise API and Volunteer API use the same Authorization: Bearer header format, but tokens are not interchangeable across products. Each product’s authentication is independent — partner integrations spanning multiple Virtuous products store and route a separate credential for each.

Next steps

Base URLs and Environments

The base URL, why there is no sandbox environment, and how to scope credentials per customer.

Make Your First API Call

A walkthrough of request anatomy, response inspection, and debugging your first call.

Error Handling

The error response shape and how to write defensive client code.

Rate Limits

The 5,000-requests-per-hour limit and how to handle 429 responses gracefully.
Last modified on June 4, 2026