> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.awardspring.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.awardspring.com/_mcp/server.

# List people.

GET https://api.awardspring.com/api/v1/people

Returns the people the institution's Users list shows, for the institution your API key is issued
for, in the standard list envelope (`object: "list"`, `has_more`, `next_cursor`,
`previous_cursor`, `data`). Each person carries their roles, the departments an
administrator is limited to, whether the account is archived, and an administrator's permissions.
Page forward by passing the returned `next_cursor` as `starting_after`. `limit`
defaults to 25 and is capped at 100. Results are ordered by id ascending.


Filter with `?role=` (`administrators`, `reviewers`, `students` or
`donors`), `?q=` (part of a name, the start of an email address or student number, or an
exact id) and `?status=` (`all`, `active` or `archived`; archived accounts are
listed by default, as on the Users list).


Reference: https://docs.awardspring.com/api-reference/people/list

## Authentication

- `X-Spring-API-Key` header (required) — Secret API key issued per institution. Send it on every request.

## Servers

- `https://api.awardspring.com` (UnitedStates, default)
- `https://api.awardspring.ca` (Canada)

## Request

### Query parameters

- `role` (string, optional) — Which tab of the Users list (`?role=`): `administrators`, `reviewers`, `students` or `donors`. The reviewers tab also lists anyone on a review group in the current award cycle.
- `q` (string, optional) — Free-text search (`?q=`): matches part of a first or last name or organization, the start of an email address or student number, or a person's exact `id`.
- `status` (string, optional) — Account status (`?status=`): `all` (the default, as the Users list shows), `active` or `archived`.
- `limit` (integer, optional, default: 25) — Page size. Defaults to 25. Values outside 1–100 are clamped rather than rejected.
- `starting_after` (string, optional) — Opaque cursor. Pass the `next_cursor` from the previous page to page forward. Mutually exclusive with `ending_before`; if both are supplied, `starting_after` wins.
- `ending_before` (string, optional) — Opaque cursor. Pass the `previous_cursor` from the current page to page backward.
- `include` (list of enum, optional) — Optional extras to add to the response, comma-separated. `total_count` is the only supported value: it adds `total_count`, the number of records that match this request across all pages. The count is taken fresh at the moment of each request, so it can change while you page; ask for it on the first page. Without it, `total_count` is left out of the response. Asking or not never invalidates a cursor. Any other value returns `400 validation_failed`.
  - Allowed values: `total_count`

## Response

### 200

OK

- `object` (string, optional, nullable) — Discriminator constant. Always `"list"`, mirroring Stripe's list objects.
- `url` (string, optional, nullable) — The request path this collection was served from (e.g. `/api/v1/scholarships`).
- `has_more` (boolean, optional) — True when another page exists in the current paging direction.
- `next_cursor` (string, optional, nullable) — Opaque cursor for the next page (pass as `starting_after`). Null when there is none.
- `previous_cursor` (string, optional, nullable) — Opaque cursor for the previous page (pass as `ending_before`). Null when there is none.
- `total_count` (integer, optional, nullable) — The number of records that match the request across all pages, counted fresh on each request. Present only when the request includes `include=total_count`; otherwise the key is omitted.
- `data` (list of PersonV1, optional, nullable) — The page of items.

## Errors

### 400 Bad Request Error

Bad Request

- `error` (V1ErrorBody, optional) — Stripe-shaped error object for the `/api/v1/*` surface. Serialized snake\_case (via V1SnakeCaseNamingStrategy) and always nested under the `error` key of a V1ErrorEnvelope: `{ "error": { "type": "...", "code": "...", "message": "...", "param": null, "doc_url": null, "recovery": "..." } }`

### 403 Forbidden Error

Forbidden

- `error` (V1ErrorBody, optional) — Stripe-shaped error object for the `/api/v1/*` surface. Serialized snake\_case (via V1SnakeCaseNamingStrategy) and always nested under the `error` key of a V1ErrorEnvelope: `{ "error": { "type": "...", "code": "...", "message": "...", "param": null, "doc_url": null, "recovery": "..." } }`

### 429 Too Many Requests Error

Rate limit exceeded for this API key. Retry after the interval in the `Retry-After` header.

- `error` (V1ErrorBody, optional) — Stripe-shaped error object for the `/api/v1/*` surface. Serialized snake\_case (via V1SnakeCaseNamingStrategy) and always nested under the `error` key of a V1ErrorEnvelope: `{ "error": { "type": "...", "code": "...", "message": "...", "param": null, "doc_url": null, "recovery": "..." } }`

## Types

### PersonV1

One person with an account at the institution, as the institution's Users list shows them.

- `object` (string, optional, nullable) — Stripe-style resource discriminator. Stable, snake_case string naming the resource type. Serialized first so it reads as the leading field of every V1 resource body.
- `id` (string, optional, nullable) — The stored ID of the person's user record.
- `first_name` (string, optional, nullable)
- `last_name` (string, optional, nullable)
- `email` (string, optional, nullable)
- `role` (enum, optional, nullable) — The person's main role: `super_administrator`, `administrator`, `department_admin`, `reviewer`, `student`, `recommender`, `donor`, `organization` or `client_service_admin`.
  - Allowed values: `super_administrator`, `administrator`, `department_admin`, `reviewer`, `student`, `recommender`, `donor`, `organization`, `client_service_admin`, `awardspring_staff`
- `roles` (list of string, optional, nullable) — Every role the person holds: the main role first, then any other role on the same account.
- `departments` (list of PersonDepartmentV1, optional, nullable) — The departments an administrator is limited to. An administrator with departments works only with what belongs to those departments. An empty list means the person is not limited to departments, except for a `department_admin`, who is always limited and reaches no department until one is listed here.
- `is_archived` (boolean, optional) — True when the account is archived: the person cannot sign in until it is restored.
- `permissions` (list of PersonPermissionCategoryV1, optional, nullable) — What the administrator may use, as their Permissions tab shows it. Null for anyone the Permissions tab does not manage: Super Administrators, people who are not administrators, and every person at an institution where all administrators have full access.

### V1ErrorBody

Stripe-shaped error object for the `/api/v1/*` surface. Serialized snake\_case (via V1SnakeCaseNamingStrategy) and always nested under the `error` key of a V1ErrorEnvelope: `{ "error": { "type": "...", "code": "...", "message": "...", "param": null, "doc_url": null, "recovery": "..." } }`

- `type` (string, optional, nullable) — Coarse error category from V1ErrorType (e.g. `invalid_request_error`).
- `code` (string, optional, nullable) — Stable fine-grained machine code from ErrorCode (e.g. `donor_not_found`).
- `message` (string, optional, nullable) — Human-readable summary safe to surface to the caller.
- `param` (string, optional, nullable) — The request parameter the error relates to, when attributable to a single field; otherwise null.
- `doc_url` (string, optional, nullable) — Link to documentation for this error, when one exists; otherwise null.
- `recovery` (string, optional, nullable) — Plain-language guidance on how to recover from this error, suitable for showing to the person who triggered it. Not present on every error.
- `details` (any, optional) — Optional structured payload (e.g. a list of ValidationDetail for validation failures). Omitted from the wire when null so the canonical Stripe shape stays minimal.

### PersonDepartmentV1

A department a person is limited to.

- `object` (string, optional, nullable) — Stripe-style resource discriminator. Stable, snake_case string naming the resource type. Serialized first so it reads as the leading field of every V1 resource body.
- `id` (string, optional, nullable) — The department's stored ID, as `GET /api/v1/departments` lists it.
- `name` (string, optional, nullable)

### PersonPermissionCategoryV1

One area on an administrator's Permissions tab, such as Scholarships or Users.

- `object` (string, optional, nullable) — Stripe-style resource discriminator. Stable, snake_case string naming the resource type. Serialized first so it reads as the leading field of every V1 resource body.
- `category` (string, optional, nullable) — The area's stable key, for example `scholarships`.
- `name` (string, optional, nullable) — The area's name as the Permissions tab shows it.
- `enabled` (boolean, optional) — True when the administrator may use this area at all.
- `items` (list of PersonPermissionV1, optional, nullable) — The finer permissions inside the area. Empty when the area has none.

### PersonPermissionV1

One finer permission inside an area of the Permissions tab.

- `object` (string, optional, nullable) — Stripe-style resource discriminator. Stable, snake_case string naming the resource type. Serialized first so it reads as the leading field of every V1 resource body.
- `key` (string, optional, nullable) — The permission's stable key, for example `scholarships.qualifications`.
- `name` (string, optional, nullable) — The permission's name as the Permissions tab shows it.
- `access` (enum, optional, nullable) — The administrator's access: `none`, `view` or `edit` for a permission with access levels, and `no` or `yes` for a permission that is simply on or off.
  - Allowed values: `none`, `view`, `edit`, `no`, `yes`

## Examples

**Response**

```json
{
  "object": "string",
  "url": "string",
  "has_more": true,
  "next_cursor": "string",
  "previous_cursor": "string",
  "total_count": 1,
  "data": [
    {
      "object": "string",
      "id": "string",
      "first_name": "string",
      "last_name": "string",
      "email": "string",
      "role": "super_administrator",
      "roles": [
        "string"
      ],
      "departments": [
        {
          "object": "string",
          "id": "string",
          "name": "string"
        }
      ],
      "is_archived": true,
      "permissions": [
        {
          "object": "string",
          "category": "string",
          "name": "string",
          "enabled": true,
          "items": [
            {
              "object": "string",
              "key": "string",
              "name": "string",
              "access": "none"
            }
          ]
        }
      ]
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.awardspring.com/api/v1/people"

headers = {"X-Spring-API-Key": "<apiKey>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.awardspring.com/api/v1/people';
const options = {method: 'GET', headers: {'X-Spring-API-Key': '<apiKey>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.awardspring.com/api/v1/people"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("X-Spring-API-Key", "<apiKey>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.awardspring.com/api/v1/people")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["X-Spring-API-Key"] = '<apiKey>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.awardspring.com/api/v1/people")
  .header("X-Spring-API-Key", "<apiKey>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.awardspring.com/api/v1/people', [
  'headers' => [
    'X-Spring-API-Key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.awardspring.com/api/v1/people");
var request = new RestRequest(Method.GET);
request.AddHeader("X-Spring-API-Key", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["X-Spring-API-Key": "<apiKey>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.awardspring.com/api/v1/people")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```