Trusted Partner: Accounts Registration API
Introduction: Registering Organizations via Accounts API
An organization that has been designated as a trusted partner with authority may use the accounts Organization Register API to add their partner organizations.
Trusted Third Party with Authority workflow is defined as: The trusted third party has authorization to publish for the data organization, without the data organizations having to first create an account and give explicit authorization to the third party.
- The trusted organization, such as a state body, registers with the CE accounts site. Under their organization information, they would indicate that they plan to act as a third party publisher.
- This organization will likely have already had meetings with the CE team to discuss their plans. A CE team member has to designate an organization as a trusted partner.
- The trusted partner is responsible for validation of the organizations for whom they will be publishing.
- Typically the trusted partner will use either the accounts API endpoint or a bulk upload in the accounts site to register the organizations for whom they will be publishing.
-
Both the API endpoint or bulk upload process will:
- Validate the data
- At least one contact is required. This person will be added as an administrator for the new organization.
- The administrator will receive an email requesting confirmation of their account. This administrator can add additional contacts as needed.
- The organization will be created, approved, and assigned an API key for publishing.
- A third party relationship will be created and approved for publishing.
-
The provided contact will receive an email as notification that their organization has been added by the trusted partner.
NOTE: when testing in the sandbox, an organization may not want to send emails to the target organization contacts. The API parameter: SendingOrgContactEmails can be used. If this property is set to false, then no emails will be sent.
June 2023 This property can now be also used in production.
- When publishing the third party organization would use their API key and the CTID for one of the client organizations as the PublishForOrganizationIdentifier parameter when publishing to the registry.
- The Assistant API process will validate whether a particular API key can be used to publish data for a particular organization CTID.
Calling the Register Organization Endpoint
Make an HTTP POST
to the following API endpoint to register organizations:
https://apps.credentialengine.org/accountsapi/organization/register
Include your organization's API key in the header:
Authorization: ApiToken [YOUR API KEY]
Sample:
using ( var client = new HttpClient() )
{
client.DefaultRequestHeaders.
Accept.Add( new MediaTypeWithQualityHeaderValue( "application/json" ) );
//Add Authorization header
client.DefaultRequestHeaders.Add( "Authorization", "ApiToken " + "YOUR API KEY" );
//........
}
Endpoint Steps
The register endpoint will perform the following steps:
- Verify caller is a trusted partner (using the API Key)
- Validate the request
- If valid, add the organization
- If the contact doesn’t exist (based on the contact email address), create the user
- Add the provided contact as an administration user to the organization
- Approve the organization
- Set up and approve a third party relationship between the organization and the caller (trusted organization)
- Send emails to all parties
NOTE: when testing in the sandbox, an organization may not want to send emails to the target organization contacts. The API parameter: SendingOrgContactEmails can be used. If this property is set to false, then no emails will be sent.
June 2023 This property can now be also used in production.
Managing Existing Organizations
There may be cases where an organization for which your organization will be publishing on behalf of, already exists in the accounts site and likely in the Credential Registry. In this case, you can still perform the third party publishing on their behalf for data likely from a different state than other third party publishers.
However there will be a different workflow for this scenario:
- If an organization exists, the API will return a message along with the CTID for the existing organization in the property: ExistingOrganizationCTID. You must store this CTID in your system (rather than the one you might have originally used when trying to register).
-
You would then repeat the register transaction with the existing provided CTID:
- You will not be able to update any core data (name, URL, address, etc.) for the organization (this step would be ignored)
- Any contacts in the register transaction will NOT be added to the target organization
- The publishing third party relationship will still be set up and approved
Validate Endpoint
Publishing resources:
- You will NOT be able to publish the organization directly (an error will occur if attempted)
- The process for publishing other resources would be unchanged.
Organization
The CTID for an organization is required to be specified as the owning organization when publishing any data to the registry.
uniqueidentifer
. So the uniqueidentifier with the prefix of ce- could be used.ce-c427f875-a123-b456-c789-9c6b9ef2143d
- ManualEntry
- BulkUpload
- CompetencyFrameworks
info@organization.net
800-555-1212
x123
800-555-1213
x456
profile_f492597f-9b33-4205-b49c-8f6f09a9c466
- Must not already be in use by another organization
SpringfieldU
- CredentialOrganization
- QACredentialOrganization
- CompetencyFrameworkOrganization
CredentialOrganization
- RegistryAssistant
- ManualEntry
- BulkUpload
- CompetencyFrameworks
NOTE: if any of the latter three are selected, the organization will be sync'd to the CE Publisher site. Generally, if organization information will only be published to the Credential Registry using the Registry Assistant, then only RegistryAssistant should be selected.
RegistryAssistant
- CreateWidget
- SearchApi
- OfflineStorage
SearchApi
- PrivateNonProfit
- PrivateForProfit
- Public
Public
The complete list:
- Alternative/Non-Traditional School
- Assessment Body
- Business or Industry Association
- Business
- Career and Technical School
- Certification Body
- Collaborative
- Coordinating Body
- Education and Training Provider
- Four-Year College
- Government Agency
- High School
- Labor Union
- Magnet/Competitive Admissions School
- Military
- Postsecondary Educational Institution
- Primarily Online
- Professional Association
- Quality Assurance Body
- Secondary School
- Two-Year College
- Vendor
https://credreg.net/ctdl/terms/OrganizationType#OrganizationType
Education and Training Provider | Four-Year College
AdminContact
List of Admin Contacts. At least one contact must be included.
If a contact is not known for the target organization, then provide a person from the staff of the requesting organization. All contacts will receive notifications regarding updates to the organization and summary emails when data is published for the organization.
NOTE: If the third party organization will be responsible for managing the data in the accounts site, then always use a contact from the third party.
info@organization.net
800-555-1212
x123
PublishingEstimate
ceterms:Certificate
Response
Sample API Input
{
"Name": "This Community College",
"Description": "Description of This Community College",
"Ctid": "ce-xxxxxxxx-1220-001c-xxxx-d45917a407ac",
"Url": "https://example.com/yourTest/",
"FEIN": "xx-1234567",
"PrimaryEmail": "test@test.com",
"PrimaryPhoneNumber": "(800) 555-1212",
"OrganizationPublishingRoleUris": [
"CredentialOrganization"
],
"OrganizationPublishingMethodUris": [
"RegistryAssistant"
],
"OrganizationConsumingMethodUris": [
"SearchApi"
],
"OrganizationTypeUris": [
"orgType:TwoYear","certificationBody"
],
"OrganizationSectorUri": "agentSector:Public",
"Contacts": [
{
"Email": "test@your.org",
"FirstName": "John",
"LastName": "AdminUser"
}
],
"StreetAddress": "1375 S Clare Avenue",
"City": "Harrison",
"StateProvince": "Michigan",
"PostalCode": "48625",
}
Sample C# Input Class
public class OrganizationAddition
{
// Required
public string CTID { get; set; }
// Required
public string Name { get; set; }
// Optional unless publishing methods include any of: ManualEntry, BulkUpload, or CompetencyFramework
public string Description { get; set; }
// Organization Profile name
// Max of 50 characters, must be unique to the accounts site
// If blank, will be set to default of profile-GUID
// IF NOT SURE IT WILL BE UNIQUE - DON'T INCLUDE
public string ProfileName { get; set; }
// Recommended, but no longer required for registrations by trusted partners
public string FEIN { get; set; }
public string DUNS { get; set; }
public string OPEID { get; set; }
// Required Primary URL for the organization
public string Url { get; set; }
// Required
public string PrimaryPhoneNumber { get; set; }
public string PrimaryPhoneExtension { get; set; }
public string SecondaryPhoneNumber { get; set; }
public string SecondaryPhoneExtension { get; set; }
public string PrimaryEmail { get; set; }
// OrganizationPublishingRoleUris
// One or more of
// - CredentialOrganization,
// - QACredentialOrganization,
// - CompetencyFrameworkOrganization
// Required
public List<string> OrganizationPublishingRoleUris { get; set; } = new List<string>();
// OrganizationPublishingMethodUris
// One or more of
// - BulkUpload
// - CompetencyFrameworks
// - ManualEntry
// - RegistryAssistant
// Required
public List<string> OrganizationPublishingMethodUris { get; set; } = new List<string>();
// OrganizationConsumingMethodUris
// Zero or more of
// - CreateWidget
// - OfflineStorage
// - SearchApi
// Required
public List<string> OrganizationConsumingMethodUris { get; set; } = new List<string>();
// OrganizationType concept scheme
// See: https://credreg.net/ctdl/terms/OrganizationType#OrganizationType
// Required
public List<string> OrganizationTypeUris { get; set; } = new List<string>();
// OrganizationSector concept scheme
// One of (defaults to Public)
// - PrivateNonProfit
// - PrivateForProfit
// - Public
// Required
public string OrganizationSectorUri { get; set; }
/// <summary>
/// If false, do NOT send emails to confirm accounts.
/// June 2023 This property can now be also used in production.
/// </summary>
public bool? SendingOrgContactEmails { get; set; } = true;
// List of contacts for this organization
// At least one contact is required
public List<AdminContact> Contacts { get; set; } = new List<AdminContact>();
// Properties for Address
// All required
public string StreetAddress { get; set; }
public string City { get; set; }
public string StateProvince { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
// Optional
public List<PublishingEstimate> PublishingEstimates { get; set; } = new List<PublishingEstimate>();
}
public class PublishingEstimate
{
public string EntityTypeUri { get; set; }
public int EstimatedCount { get; set; }
public string Comment { get; set; }
}
public class AdminContact
{
public string Email { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string DaytimePhoneNumber { get; set; }
public string DaytimePhoneExtension { get; set; }
}
Calling the API - Sample C# Code
The following is sample C# code for calling the API.
// For serialization/deserialization methods
using Newtonsoft.Json;
public void RegisterOrganization()
{
string publisherApikey = “provide your api key here”;
// URL for sandbox
var accountsApiUrl = “https://sandbox.credentialengine.org/accountsAPI/organization/register”;
// Provide a valid CTID
string ctid = "ce-????????-????-????-????-????????????";
API.OrganizationAddition org = new API.OrganizationAddition()
{
Name = "Delta College",
Url = "http://example.com/DeltaCollege",
// Max length = 50. Must be unique. Leave blank to have system set a default.
ProfileName = "profile_" + Guid.NewGuid().ToString().ToLowerInvariant(),
CTID = ctid,
FEIN = "??-nnnnnnn",
DUNS = "",
OPEID = ""
};
// Add a publishing role (with or without the namespace of publishRole)
org.OrganizationPublishingRoleUris.Add("publishRole:CredentialOrganization");
// Add one or more publishing methods
org.OrganizationPublishingMethodUris.Add("ManualEntry");
org.OrganizationPublishingMethodUris.Add("publishMethod:RegistryAssistant");
// Add one sector
org.OrganizationSectorUri = "agentSector:Public";
// Add one or more organization types
org.OrganizationTypeUris.Add("orgType:TwoYear" );
org.PrimaryEmail = "test@email.com";
org.PrimaryPhoneNumber = "800-555-1212";
// Add an administrator for the new organization
org.Contacts.Add( new AdminContact()
{
Email = "adminUser@myEmail.org",
FirstName = "My",
LastName = "Name"
} );
org.StreetAddress = "1961 Main Str";
org.City = "Somewhere";
org.StateProvince = "Michigan";
org.PostalCode = "48710";
org.Country = "USA";
// Call accounts API
string contents = "";
// Serialize
string postBody = JsonConvert.SerializeObject(org, GetJsonSettings());
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", "ApiToken " + publisherApikey);
var task = client.PostAsync(accountsApiUrl,
new StringContent(postBody, Encoding.UTF8, "application/json"));
task.Wait();
var response = task.Result;
contents = task.Result.Content.ReadAsStringAsync().Result;
// Deserialize to the response object (or could use a Dictionary object);
var orr = JsonConvert.DeserializeObject(contents);
if (response.IsSuccessStatusCode == false)
{
// Inspect messages individually or place all in a string
var status = string.Join("", orr.Messages.ToArray());
} else
{
// Check to ensure OK
// {
// "Successful":true,
// "Messages":[],
// "OrganizationApiKey":"????????-????-????-????-????????????",
// "ApprovedToPublish":true
// }
}
}
// End using
}
catch (Exception ex)
{
// Handle errors, while very unlikely
LoggingHelper.LogError(ex, string.Format(thisClassName + ".TestRegisterOrganization FAILED. Publisher OrgName: {0}, target orgCtid", org.Name, org.CTID));
string message = LoggingHelper.FormatExceptions(ex);
}
}
public static JsonSerializerSettings GetJsonSettings()
{
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
return settings;
}