Crews.PlanningCenter.Api
2.0.0
Prefix Reserved
dotnet add package Crews.PlanningCenter.Api --version 2.0.0
NuGet\Install-Package Crews.PlanningCenter.Api -Version 2.0.0
<PackageReference Include="Crews.PlanningCenter.Api" Version="2.0.0" />
<PackageVersion Include="Crews.PlanningCenter.Api" Version="2.0.0" />
<PackageReference Include="Crews.PlanningCenter.Api" />
paket add Crews.PlanningCenter.Api --version 2.0.0
#r "nuget: Crews.PlanningCenter.Api, 2.0.0"
#:package Crews.PlanningCenter.Api@2.0.0
#addin nuget:?package=Crews.PlanningCenter.Api&version=2.0.0
#tool nuget:?package=Crews.PlanningCenter.Api&version=2.0.0
.NET Planning Center API Library
A client library for the Planning Center API built on the JSON:API Framework.
Installation
Crews.PlanningCenter.Api
is available on NuGet:
dotnet add package Crews.PlanningCenter.Api
Configuration
This library uses the options pattern. By default, the following configuration sections are defined:
Authentication:PlanningCenter
: mapped to thePlanningCenterOAuthOptions
class. Used for defining OAuth credentials.PlanningCenterApi
: mapped to thePlanningCenterApiOptions
class. Used for defining all other options for the library.
OAuth Options
The following are valid options for OAuth authentication:
Option Name | Type | Description |
---|---|---|
ClientId |
string |
The OAuth client ID. |
ClientSecret |
string |
The OAuth client secret. |
This class also accepts all options defined in the OAuthOptions
class.
appsettings.json
example:
{
"Authentication": {
"PlanningCenter": {
"ClientId": "my-client-id",
"ClientSecret": "my-client-secret"
}
}
}
Manual configuration example:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = PlanningCenterOAuthDefaults.AuthenticationScheme;
})
.AddCookie("Cookies")
.AddPlanningCenterOAuth(options =>
{
// The strings here are hardcoded for example.
// These credentials should never be stored in your code.
options.ClientId = "my-client-id";
options.ClientSecret = "my-secret";
});
API Options
Option Name | Type | Description | Default |
---|---|---|---|
ApiBaseAddress |
Uri |
The base URL of the Planning Center API. | https://api.planningcenteronline.com |
HttpClientName |
string |
The name of an optional named HttpClient to use in the service.<br><br>NOTE: This client's BaseAddress property will be ignored in favor of the ApiBaseAddress option. |
N/A |
UserAgent |
string |
The user agent string to send on API requests. This is required by Planning Center. | Generic .NET Planning Center API Client |
PersonalAccessToken |
PlanningCenterPersonalAccessToken |
An optional Planning Center personal access token. | N/A |
appsettings.json
example:
{
"PlanningCenterApi": {
"ApiBaseAddress": "http://some-address.com",
"HttpClientName": "my-custom-client",
"UserAgent": "Some custom user agent string",
"PersonalAccessToken": {
"AppId": "my-app-id",
"Secret": "my-secret"
}
}
}
Manual configuration example:
builder.Services.AddPlanningCenterApi(options =>
{
options.ApiBaseAddress = new("http://some-address.com");
options.HttpClientName = "my-custom-client";
options.UserAgent = "Some custom user agent string";
// The strings here are hardcoded for example.
// These credentials should never be stored in your code.
options.PersonalAccessToken = new()
{
AppId = "my-app-id",
Secret = "my-secret"
};
});
Setup
This library can be used with application builders (dependency injection), or as a standalone client.
ASP.NET Core Application Builder
First, add OAuth authentication:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = PlanningCenterOAuthDefaults.AuthenticationScheme;
})
.AddCookie("Cookies")
.AddPlanningCenterOAuth(options =>
{
// Add scopes for the APIs you need access to
// By default, the "People" scope is always included
options.Scope.Clear();
options.Scope.Add(PlanningCenterOAuthScope.People);
options.Scope.Add(PlanningCenterOAuthScope.Calendar);
options.Scope.Add(PlanningCenterOAuthScope.CheckIns);
});
Next, add the Planning Center API service:
builder.Services.AddPlanningCenterApi();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
Finally, add authentication endpoints to your app. The OAuth middleware will automatically handle token management and refreshing.
app.MapGet("/login", (HttpContext context, string? returnUrl = null) =>
{
var properties = new AuthenticationProperties
{
RedirectUri = returnUrl ?? "/"
};
return Results.Challenge(properties, [PlanningCenterOAuthDefaults.AuthenticationScheme]);
});
app.MapPost("/logout", async (HttpContext context) =>
{
await context.SignOutAsync("Cookies");
return Results.Redirect("/");
});
Now you can inject IPlanningCenterApiService
into your controllers or services.
[Authorize]
public class MyController(IPlanningCenterApiService _planningCenterApi) : Controller
{
public async Task<IActionResult> Profile()
{
// API calls automatically use the authenticated user's OAuth token, or your personal access token
var currentUser = await _planningCenterApi.People.LatestVersion
.GetRelated<PersonResource>("me")
.GetAsync();
return View(currentUser.Data);
}
}
Standalone
Start by creating an HttpClient
instance:
HttpClient client = new();
client.SafelySetBaseAddress(new("https://api.planningcenteronline.com"));
// This example uses a personal access token.
// If you want to use OAuth in a standalone client, you're on your own.
PlanningCenterPersonalAccessToken token = new()
{
AppID = "yourAppIdHere",
Secret = "superSecretPasswordHere"
};
client.DefaultRequestHeaders.Authorization = token;
Use this HttpClient
to create a new API client of your choice, and you're off to the races!
CalendarClient calendar = new(client);
var myEvent = await calendar.LatestVersion.Events.WithID("123").GetAsync();
Console.WriteLine($"My event is called {myEvent.Data.Name}!");
Examples
Fluent API Example
You can chain API resource calls to navigate the API:
var myEvent = await calendar.LatestVersion
.Events
.WithID("123")
.Owner
.EventResourceRequests
.WithID("456")
.ResourceBookings
.WithID("789")
.EventInstance
.Event
.GetAsync();
Querying Example
You can easily include related resources, or sort and query collections:
var myAttachments = await calendar.LatestVersion.Attachments
.Include(AttachmentIncludable.Event)
.OrderBy(AttachmentOrderable.FileSize, Order.Descending)
.Query((AttachmentQueryable.Name, "myAttachment"), (AttachmentQueryable.Description, "The best attachment."))
.GetAllAsync();
// Reading included resources must be done manually.
var includedResources = myAttachments.JsonApiDocument.GetIncludedResources();
Pagination Example
You can specify a count and an offset for collections of resources:
var myAttachments = await calendar.LatestVersion.Attachments.GetAllAsync();
Console.WriteLine(myAttachments.Metadata.TotalCount); // Get total count of items available on the API
Console.WriteLine(myAttachments.Metadata.Next.Offset); // Get item offset for next page of items
// Get only first five items
myAttachments = await calendar.LatestVersion.Attachments.GetAllAsync(count: 5);
// Get ten items, offset by five items
myAttachments = await calendar.LatestVersion.Attachments.GetAllAsync(count: 10, offset: 5);
Mutation Example
You can also POST
, PATCH
, and DELETE
resources with these options:
var myEventConnection = calendar.LatestVersion
.Events
.WithID("123")
.EventConnections
.WithID("456");
EventConnection newConnection = new()
{
ConectedToId = "123",
ConnectedToName = "Test"
};
// POST
var postResult = await myEventConnection.PostAsync(newConnection);
// PATCH
var patchResult = await myEventConnection.PatchAsync(newConnection);
// DELETE
await myEventConnection.DeleteAsync();
Custom Resource Example
You can define your own resource types by inheriting from either PlanningCenterSingletonFetchableResource
or PlanningCenterPaginatedFetchableResource
.
This provides forward compatibility by allowing you to define and fetch any resources not yet implemented in this library.
Model Creation
First, create a model class:
[JsonApiName("my_custom_resource")]
public record MyCustomModel
{
[JsonApiName("my_first_property")]
public string? MyFirstProperty { get; init; }
[JsonProperty("my_second_property")]
public int? MySecondProperty { get; init; }
}
Next, you can create your resource class.
Singleton Resource
public class MyCustomResource
: PlanningCenterSingletonFetchableResource<MyCustomModel, MyCustomResource, PeopleDocumentContext>,
IIncludable<MyCustomResource, MyCustomResourceIncludable>
{
// In this example, your resoruce has child resources of type "people"
public PeopleResourceCollection People => GetRelated<PeopleResourceCollection>("people");
public MyCustomSingletonResource(Uri uri, HttpClient client) : base(uri, client) { }
// In this example, your resource has certain includable resources
public MyCustomResource Include(params MyCustomResourceIncludable[] included) => base.Include(included);
}
Paginated Resource
Creating a paginated resource type requires the existence of a singleton resource type for the same model.
public class MyCustomResourceCollection
: PlanningCenterPaginatedFetchableResource<MyCustomModel, MyCustomResourceCollection, MyCustomResource, PeopleDocumentContext>,
IIncludable<MyCustomResourceCollection, MyCustomResourceIncludable>,
IOrderable<MyCustomResourceCollection, MyCustomResourceOrderable>,
IFilterable<MyCustomResourceCollection, MyCustomResourceQueryable>
{
public MyCustomResourceCollection(Uri uri, HttpClient client) : base(uri, client) { }
// In this example, your resource has certain includable resources
public MyCustomResourceCollection Include(params MyCustomResourceIncludable[] included) => base.Include(included);
// In this example, your resource has certain orderable properties
public MyCustomResourceCollection OrderBy(MyCustomResourceOrderable orderable, Order order = Order.Ascending) => base.OrderBy(orderable, order);
// In this example, your resource has certain queryable properties
public MyCustomResourceCollection Query(params (MyCustomResourceQueryable, string)[] queries) => base.Query(queries);
}
Accessing your custom resources
Simply call the GetRelated<T>()
method on any singleton resource to access your custom resource:
// Singleton
var currentUser = await planningCenterApi.People.LatestVersion
.GetRelated<MyCustomResource>("my_custom_resource");
// Paginated
var customResources = await planningCenterApi.People.LatestVersion
.GetRelated<MyCustomResourceCollection>("my_custom_resources");
S.D.G.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Crews.Extensions.Http (>= 3.0.0)
- Crews.PlanningCenter.Models (>= 2.0.0)
- JsonApiFramework.Client (>= 2.13.0)
- Microsoft.Extensions.DependencyInjection (>= 9.0.1)
- Microsoft.Extensions.Http (>= 9.0.1)
- Microsoft.Extensions.Options (>= 9.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
2.0.0 | 130 | 9/25/2025 |
1.2.0 | 191 | 8/29/2025 |
1.1.0 | 142 | 1/23/2025 |
1.0.2 | 104 | 1/15/2025 |
1.0.0-preview.14 | 85 | 12/6/2024 |
1.0.0-preview.13 | 76 | 11/30/2024 |
1.0.0-preview.12 | 74 | 11/29/2024 |
1.0.0-preview.11 | 88 | 11/11/2024 |
1.0.0-preview.10 | 82 | 11/11/2024 |
1.0.0-preview.9 | 78 | 11/9/2024 |
1.0.0-preview.8 | 82 | 11/9/2024 |
1.0.0-preview.7 | 79 | 10/16/2024 |
1.0.0-preview.6 | 84 | 10/15/2024 |
1.0.0-preview.5 | 81 | 10/3/2024 |
1.0.0-preview.4 | 71 | 10/3/2024 |
1.0.0-preview.3 | 86 | 9/25/2024 |
1.0.0-preview.2 | 89 | 5/22/2024 |
1.0.0-preview.1 | 85 | 5/22/2024 |