FIFA Connect ID

.NET SDK, v4.1

1. Introduction

Main responsibility of FIFA Connect ID Service (FCI) is to generate a unique FIFA_ID for a football/futsal/beach soccer stakeholder. Football Management Systems operating in different Member Associations integrate with the FCI in order to register persons, organisations and facilities, and have FIFA_ID generated for these entities. Integration can be done in two ways: * directly - by using REST API of FCI * [recommended] via SDK, a library which wraps REST API and simplifies access to the service

This documentation is a reference point for a developer who wants to use SDK to integrate Football Management System with FCI.

Documentation is organised into three main chapters which discuss all aspects of a certain entity type management. * Chapter 3 - describes how to register, update or merge the Person. A lot of attention is paid to finding national and international duplicates for a person being registered. * Chapter 4 - discusses all aspects of Organisation registration, update and merge * Chapter 5 - shows how to register or update a Facility

Chapters 2 and 6 provide - respectively - a brief introduction to setting up the integration and an overview of latest changes to SDK.

1.1 Clarification on the class names

Class names – although sometimes confusing – follow the FIFA Data Standard and as such they cannot be subject of modification.

1.2 Unexpected Setters

Some SDK classes that represent read-only data provided by the server side (e.g. PersonDuplicateType) contain setter methods. This data isn’t normally modified on the client side. The reason to have them, however, is that the client can easily simulate possible response from service by setting values to objects – and that can be useful for testing.

1.3 Date and time

All SDK methods requires date and time in UTC time zone. If date/time passed as an argument to SDK method and is not in UTC then Exception is thrown. Consequently, all date/time objects returned from the SDK are in UTC.

Note: pay special attention to birth date so they are not affected by time zones changes. For example both person born in Chile and Japan on 1.1.2012 should be registered as born on 1.1.2012 0:00 UTC.

1.4 Thread-safety

Any instance members are not guaranteed to be thread safe. In particular all methods on FifaConnectServiceBusClient cannot be called from multiple threads simultaneously. If needed, new instance of FifaConnectServiceBusClient should be created per thread.

2. Setup

SDK libraries to reference:

3. Person

Current version of the SDK supports two approaches to operations on Person entity:

Two following sections describe implementation steps which are necessary to cover both scenarios: * Chapter 3.1 - Person registration/update/search together with a duplicate check * Chapter 3.2 - operations on Person entity not requiring a duplicate check

3.1 Using Registration Facade

The RegistrationFacade class simplifies the usage of FifaConnectIdClient and FifaConnectServiceBusClient, in order to cover full scenario of registering a person in FIFA Connect ID. If potential duplicates are found, Registration Facade will send requests for person details to other MAs using Connect Service Bus and wait for their response (with timeout). The same logic needs to apply when one tries to update Person details or search for duplicates but does not intend to register a person even if no duplicates are found.

3.1.1 (Step 1) Get FIFA identifier of your organisation and client credentials

In order to start registering entities (persons, facilities, organisations), you will need a FIFA identifier of your organisation (i.e. MA), a set of client credentials and pair of public and private certificates generated. Instruction of how to generate and upload certificate can be found in fifa-connectservicebus-certificates-generation.html. Instruction of how to create and use the 'IPrivateKeyStorage' can be found in fifa-connectservicebus-sdk-net-2.1.html, chapter 2.1.1 - Setup private certificate.

3.1.2 (Step 2) Create Registration Facade

Then create RegistrationFacade object:

var environment = ConnectIdEnvironment.Beta;
var clientCredentials = new ClientCredentials("clientId", "secretKey");
var privateKeyStorage = new YourPrivateKeyStorage();

var facade = new RegistrationFacade(environment, clientCredentials, privateKeyStorage);

3.1.3 (Step 3) Setup Service Bus listener

After creating facade, you can set up the background listener, which will listen and process new messages received from Connect Service Bus.

When BackgroundListener receives a message with a request for person's details it will call a method GetPersonDetails on PersonDetailsProvider passing FIFA ID of a person. Therefore you have to provide implementation of IPersonDetailsProvider that makes a lookup (e.g. in your database) and returns a valid PersonLocal XML from FIFA Data Standard ([http://data.fifaconnect.org]). If for any reason record for a requested person is not found or cannot be retured, PersonDetailsProvider should return null or empty string.

Code snippet below shows how to provide sample PersonDetailsProvider.

var provider = new YourPersonDetailsProvider();
var listener = facade.ConfigureListener(provider);

// start listening for new messages
await listener.RunWithTimeout(TimeSpan.FromMinutes(10)).ConfigureAwait(false);

XML below is an example of data that should be returned by PersonDetailsProvider

<?xml version="1.0" encoding="UTF-8"?>
<PersonLocal PersonFIFAId="105C3Z1" LocalFirstName="ΑΓΓΕΛΗΣ" LocalLastName="ΧΑΡΑΛΑΜΠΟΥΣ" LocalLanguage="gre" LocalCountry="CY" LocalSystemMAId="1234567" InternationalFirstName="ANGELIS" InternationalLastName="CHARALAMBOUS" Gender="male" DateOfBirth="1989-05-31" PlaceOfBirth="Larnaca" RegionOfBirth="Larnaca" CountryOfBirth="CY" Nationality="CY">
    <NationalIdentifier Identifier="GHKJKLD123132132" NationalIdentifierNature="PassportNumber" Country="CY" DateFrom="2010-08-13" DateTo="2020-08-13"/>
    <PlayerRegistration PersonFIFAId="105C3Z1" Status="active" OrganisationFIFAId="105C40I " RegistrationValidFrom="2003-04-11" RegistrationValidTo="2009-06-15" Discipline="Football" Level="Amateur"/>
    <PlayerRegistration PersonFIFAId="105C3Z1" Status="active" OrganisationFIFAId="105C40I " RegistrationValidFrom="2009-06-16" Discipline="Football" Level="Pro"/>
    <TeamOfficialRegistration PersonFIFAId="105C3Z1" Status="active" OrganisationFIFAId="105C40I" RegistrationValidFrom="2012-08-13" RegistrationValidTo="2014-08-13" Discipline="Futsal" TeamOfficialRole="Coach"/>
</PersonLocal>

3.1.4 (Step 4) [Optional] Subscribe to other events from Connect Service Bus

Additionally an instance of the BackgroundListener class exposes the following events:

These events are automatically raised by the listener. You can use them to register your own event handlers and provide additional logic for handling received messages.

listener.PersonDetailsReceived += details =>
{
    // do something with those details
};

listener.GenericMessageReceived += message =>
{
    var bytes = message.Content;
    var actionName = message.Action;
};

If a message received from Connect Service Bus is processed properly by all registered handlers (no exceptions are thrown), then the message is marked as processed and deleted from the Connect Service Bus queue. In case any handler throws an exception, a message will not be deleted from the Connect Service Bus but will be scheduled for later processing. BackgroundListener will try to process this message, but after a series of unsuccessful handles, a message will be moved to a dead messages queue, which will be monitored by FIFA Connect ID Helpdesk.

3.1.5 (Step 5) Register a new person

First create a person you want to register:

var organisationId = "id";

// setup player name(s)
var personNames = new List<PersonName>
{
    new PersonName("John", "Doe")
};

// setup birthdate
var dateOfBirth = new DateTime(1990, 10, 12);
var person = new PersonType
{
    DateOfBirth = dateOfBirth
};

// setup registrations
var registration = new PlayerRegistrationType
{
    OrganisationFIFAId = organisationId,
    Status = "active",
    Level = "Pro",
    Discipline = "Football"
};

person.PlayerRegistrations = new List<PlayerRegistrationType>
{
    registration
};

// finally create PersonData
var personData = new PersonData(personNames, person);

Then try to register a person using Registration Facade. The code snippet below shows an example handling (writing to console) of both scenarios, i.e. successful registration and potential duplicates found.

var result = await facade.RegisterPersonAndWaitForDetailsInCaseOfDuplicates(
    personData.Person.ToString(), TimeSpan.FromSeconds(10)).ConfigureAwait(false);

if (result.IsSuccessful)
{
    Console.WriteLine($"Person successfully registered with unique FIFA ID: {result.UniqueFifaId}.");
}
else {
    Console.WriteLine("Duplicates found.");

    foreach (var duplicateWithDetails in result.PersonDuplicateWithDetails)
    {
        var idOfDuplicatedPerson = duplicateWithDetails.Duplicate.PersonFifaId;
        var proximityScore = duplicateWithDetails.Duplicate.ProximityScore;
        var dataReceived = duplicateWithDetails.PersonDetails == null
            ? "<detailed person data not received from other MA - timeout>"
            : duplicateWithDetails.PersonDetails.XmlData;

        Console.WriteLine($"FIFA ID: {idOfDuplicatedPerson}, score: {proximityScore}, FIFA Data XML: {dataReceived}");
    }
}
3.1.5.1 Handling multiple names (local, international and maiden/birth names)

SDK provides support for registering a person with multiple names. Two scenarios will usually require such a feature:

Support for such a scenario depends on the way person registration is used.

XML in FIFA Data Standard

If you use RegisterPersonAsync which takes XML in FIFA Data Standard as a parameter, make sure that the following attributes of PersonLocal (PersonLocal schema) are filled:

You don't need to do anything else, as SDK will take care of parsing XML and sending data to the server.

Native SDK objects of type Fifa.ConnectId.Sdk.Core.XmlParser.Models.PersonData

In this case, before registering a person, you need to create a list of pairs of names (List<PersonName>) . The following example shows the most sophisticated scenario when a single person has both: local name, international name and maiden name provided. Although two pairs of names will be used in minority of cases and three pairs hardly ever, the example is instructive.

var internationalFirstName = "Olga";
var internationalLastName = " Terekhova";
var localFirstName = "Ольга";
var localLastName = "Терехова";
var localMaidenName = "Бессолова";

var personInternationalName = new PersonName(internationalFirstName, internationalLastName);
var personLocalName = new PersonName(localFirstName, localLastName);
var personMaidenName = new PersonName(localFirstName, localMaidenName);

// setup player name(s)
var personNames = new List<PersonName>();

personNames.Add(personInternationalName);
personNames.Add(personLocalName);
personNames.Add(personMaidenName);

3.1.6 Update person

First create two persons and register them:


// setup player name(s)
var person1Names = new List<PersonName>
{
    new PersonName("John", "Doe")
};
var person2Names = new List<PersonName>
{
    new PersonName("John", "Kowalsky")
};

// setup birthdate
var dateOfBirth = new DateTime(1990, 10, 12);
var person = new PersonType
{
    DateOfBirth = dateOfBirth
};

// setup registrations
var registration = new PlayerRegistrationType
{
    OrganisationFIFAId = organisationId,
    Status = "active",
    Level = "Pro",
    Discipline = "Football"
};

person.PlayerRegistrations = new List<PlayerRegistrationType>
{
    registration
};

// finally create PersonData
var person1Data = new PersonData(person1Names, person);
var person2Data = new PersonData(person2Names, person);

//register two different players
facade.ForceRegisterPerson(person1Data);
facade.ForceRegisterPerson(person2Data);

Then try to update second person using Registration Facade with names of first person. The code snippet below shows an example handling (writing to console) of both scenarios, i.e. successful update and potential duplicates found.

var result = await facade.UpdatePersonAndWaitForDetailsInCaseOfDuplicates(personId, TimeSpan.FromSeconds(10), names, dateOfBirth).ConfigureAwait(false);

if (result.IsSuccessful)
{
    Console.WriteLine($"Person updated successfully.");
}
else
{
    Console.WriteLine("Duplicates found.");

    foreach (var duplicateWithDetails in result.PersonDuplicateWithDetails)
    {
        var idOfDuplicatedPerson = duplicateWithDetails.Duplicate.PersonFifaId;
        var proximityScore = duplicateWithDetails.Duplicate.ProximityScore;
        var dataReceived = duplicateWithDetails.PersonDetails == null
            ? "<detailed person data not received from other MA - timeout>"
            : duplicateWithDetails.PersonDetails.XmlData;

        Console.WriteLine($"FIFA ID: {idOfDuplicatedPerson}, score: {proximityScore}, FIFA Data XML: {dataReceived}");
    }
}

3.1.7 [Optional] Get person duplicates (without registering)

If you need to get list of duplicates for a person, method GetDuplicatesAndWaitForDetailsInCaseOfDuplicates can be used. This methods looks for duplicates in Connect ID service. If any duplicate is found requests for person details are sent to relevant MAs.


var foundDuplicates = await facade.GetDuplicatesAndWaitForDetailsInCaseOfDuplicates(personData, TimeSpan.FromSeconds(10)).ConfigureAwait(false);

if (foundDuplicates.Count > 0)
{
    Console.WriteLine("Duplicates found.");

    foreach (var duplicateWithDetails in foundDuplicates)
    {
        var idOfDuplicatedPerson = duplicateWithDetails.Duplicate.PersonFifaId;
        var proximityScore = duplicateWithDetails.Duplicate.ProximityScore;
        var dataReceived = duplicateWithDetails.PersonDetails == null
            ? "<detailed person data not received from other MA - timeout>"
            : duplicateWithDetails.PersonDetails.XmlData;

        Console.WriteLine($"FIFA ID: {idOfDuplicatedPerson}, score: {proximityScore}, FIFA Data XML: {dataReceived}");
    }
}

3.1.8 [Optional] Multi-server scenario

If your infrastructure for the application using SDK consists of multiple servers, then additional configuration is required. In such setup RegistrationFacade needs a kind of storage where it can store state of communication with Connect Service Bus. In order to achieve SDK has interface PersonDetailsCache which must be implemented by the client of SDK and passed into RegistrationFacadeSettings.

Examples of implementation of PersonDetailsCache are:

Code snippet below presents how to register YourSharedStorage in RegistrationFacade:

var settings = new RegistrationFacadeSettings
{
    PersonDetailsCache = new YourSharedStorage()
};

var facade = new RegistrationFacade(environment, clientCredentials, settings);

In the above example YourSharedStorage implements mentioned PersonDetailsCache interface by providing three methods:

public interface IPersonDetailsCache
{
    /// <summary>
    /// Puts person details into storage mechanism.
    /// </summary>
    void Put(PersonDetails personDetails);

    /// <summary>
    /// Get person details with given correlation id from storage mechanism.
    /// </summary>
    PersonDetails GetByCorrelationId(string correlationId);

    /// <summary>
    /// Deletes the entries from storage mechanism that are older than given date.
    /// </summary>
    void DeleteOlderThan(TimeSpan duration);
}

3.1.9 Known limitations of Registration Facade

Available operations

Registration Facade covers scenario of person registration/update/search, but for other functionalities FIFA ID Client described in the next chapter must be used.

In particular FIFA Connect ID Client must be used for:

Concurrent requests

Currently there is no request throttling in API, but it's recommended not to exceed 10 concurrent connections. Too many requests to API may result in requests time outs. In case you plan to do a batch import of person records, please contact support team so that the infrastructure can be scaled up accordingly.

3.2 Using FIFA Connect ID Client

This chapter discusses all operations on a Person entity, e.g. Registration, Update, Merge, etc. It is different from chapter 3.1 Using Registration Facade in that operations described here do not involve a duplicate check. A developer who wants to perform a duplicate check via Service Bus should either refer to chapter 3.1 or implement communication via Service Bus by themselves.

3.2.1 Creating a client

The entry point of the SDK is FifaConnectIdClient. With a single instance of this class all the requests can be made. In order to authenticate to the service you have to provide a set of client credentials.

3.2.1.1 Basic instance
var environment = ConnectIdEnvironment.Beta;
var credentials = new ClientCredentials("clientId", "secretKey");

var client = new FifaConnectIdClient(environment, credentials);

where environment is an instance of type ConnectIdEnvironment. It provides information about the service to make request to.

3.2.1.2 Logging

By default, the above constructor uses a NullLogger, which does nothing. However, to use logging, provide your own implementation of ILogger.

ILogger logger = new YourOwnLogger();
var client = new FifaConnectIdClient(environment, clientCredentials, logger);
3.2.1.3 Actor

In addition you can provide information about the current user interacting with the Registration System. This can be accomplished by providing implementation of IActorResolver interface. Such actor resolver could be much more advanced than SimpleActorResolver provided as a default implementation. In case of web application, actor could be fetched from current web request context.

IActorResolver actorResolver = new SimpleActorResolver("John Doe");
var client = new FifaConnectIdClient(environment, clientCredentials, logger, actorResolver);

3.2.2 Registering a person

In order to register a person in FIFA Connect ID service, provide a properly formatted xml string. The root of the xml should be PersonLocal, not PersonData. It is required to define a local name in the document by giving LocalFirstName and LocalLastName attributes. In addition to that, LocalBirthName can by used - in that case the pair of names will be created together with LocalFirstName. International version (optional) of the name can by specified with attributes InternationalFirstName and InternationalLastName. See details:

And an example:

try
{
    var uniqueFifaId = await client.RegisterPersonAsync(xml);
}
catch (XmlException ex)
{
    // the delivered XML is malformed
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaDuplicatedEntityFoundException ex)
{
    // possible duplicates were found
    var duplicates = ex.GetDuplicatesResponseType.Duplicates;
}
catch (FifaConnectIdException ex)
{
    // some other error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}
3.2.2.1 POCO for person data

Instead of using XML files, you can also populate fields of the PersonData object yourself. For your convenience all the methods accepting XML as an input also accept PersonData directly. Here is an example, analogical to 3.2.2:

var names = new[]
{
   new PersonName("ΑΓΓΕΛΗΣ", "ΧΑΡΑΛΑΜΠΟΥΣ"), // local name
   new PersonName("ANGELIS", "CHARALAMBOUS") // international name
};

var person = new PersonType
{
   DateOfBirth = new DateTime(1980, 10, 10, 0, 0, 0, DateTimeKind.Utc),
   // fill up registrations
};

var personData = new PersonData(names, person);

try
{
   var uniqueFifaId = await client.RegisterPersonAsync(personData);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
   // data sent to the service was invalid
   var details = ex.BadRequestResponse;
}
catch (FifaDuplicatedEntityFoundException ex)
{
   // possible duplicates were found
   var duplicates = ex.GetDuplicatesResponseType.Duplicates;
}
catch (FifaConnectIdException ex)
{
   // some other error occurred, see the details
   var operationResponse = ex.HttpOperationResponse;
}
3.2.2.2 Person bulk registration

In order to register persons in parallel you can use Task Parallel Library. Please note that in order to optimize costs of test environment we keep it small-scale. Let us know upfront if you plan to test bulk registration, so we can scale up the environment. Additionally we recommend not exceeding 20 concurrent registrations to avoid performance degradation of the service. Take a look at the following example:

var database = new LocalDatabase();
var players = database.Players.Where(x => x.FifaId == null);

players
    .AsParallel()
    .WithDegreeOfParallelism(10)
    .ForAll(player =>
    {
        PersonData personData = CreatePerson(player);
        string fifaId = client.RegisterPersonAsync(personData).Result;

        database.UpdateFifaId(player.Id, fifaId);
    });

3.2.3 Force registration

To force the registration process (proceed even if potential duplicates are found):

try
{
    var uniqueFifaId = await client.ForceRegisterPersonAsync(xml);
}
catch (XmlException ex)
{
    // the delivered XML is malformed
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaConnectIdException ex)
{
    // some other error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

3.2.4 Getting person data

This method will throw FifaPersonMergedException when you try to get data for a person that has been previously merged (refer to section 4.5 Merging persons). The exception will contain data about requested person together with primary person id. To get the information associated with the specified FIFA ID such as a date of birth or list of person's registrations:

try
{
    var uniqueFifaId = "BVGE8T6";
    var person = await client.GetPersonAsync(uniqueFifaId);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the person
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaPersonMergedException ex)
{
    // requested person has been merged
    var person = ex.RequestedEntity;
    var primaryPersonId = ex.PrimaryEntityId;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

3.2.5 Merging/unmerging persons

To merge two persons into a single one use MergePersonsAsync method available on FifaConnectIdClient. This affects getting secondary person data in the future. Please refer to section 3.2.4 Getting person data. Here is an example how to merge persons:

try
{
    var person = await client.MergePersonsAsync(primaryPersonId, secondaryPersonId).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find one of specified persons
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

In order to revert merge operation call UnmergePersonsAsync method with the same arguments.

3.2.6 Getting duplicates

To get a list of people a person may be duplicated with:

try
{
    var potentialDuplicates = await client.GetDuplicatesAsync(xml);
}
catch (XmlException ex)
{
    // the delivered XML is malformed
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

This method is expected to be used rarely, e.g. in cases when Registration System chooses to do a duplicate check without the registration.

XML is the same as described in 3.2.2.

3.2.7 Add/Update/Remove registrations

It is possible to update an existing person record (provided that we know the person's FIFA ID) by adding, editing or removing its registrations. In order to do that, use the class AddRegistrationsRequestType, UpdateRegistrationsRequestType or RemoveRegistrationsRequestType (depending on the operation) and fill information about the registrations. Note, that each person always contains four collections of registrations:

In the examples below, only player registrations are used - the other 3 collections remain empty (they are not set).

3.2.7.1 Add registrations

Add a single player registration to an existing person with a given ID. Note that in the example below a registration is added in a National Association and not in a Club. This is not a coincidence - FIFA Connect ID Service, although allowed to store Clubs in general, is not allowed to store persons' assignments to Clubs. Server will return an error should the Client try to register a person within a Club.

const string personId = "105C408";
const string organisationId = "105KYBB";

var exampleRegistration = new PlayerRegistrationType();
exampleRegistration.Level = "Pro";
exampleRegistration.Discipline = "Football";
exampleRegistration.OrganisationFIFAId = organisationId;
exampleRegistration.Status = "Active";

var personRegistrations = new PersonRegistrationsType();
personRegistrations.PlayerRegistrations = new List<PlayerRegistrationType>();
personRegistrations.PlayerRegistrations.Add(exampleRegistration);

var request = new AddRegistrationsRequestType(personId, personRegistrations);

try
{
    var personType = await client.AddRegistrations(request, false).ConfigureAwait(false);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the person
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}
3.2.7.2 Update registrations

Update single player registration. In order to execute a request we need to know the registrations we need to update and their new values. Note that the order of registrations is important. Operation will try to change the first item in "old" list with the first item in the "new" list, etc.

const string personId = "105C408";
const string organisationId = "105KYBB";

var person = await client.GetPersonAsync(personId).ConfigureAwait(false);

var oldPersonRegistrations = new PersonRegistrationsType();
oldPersonRegistrations.PlayerRegistrations = person.PlayerRegistrations;

var newPlayerRegistration = new PlayerRegistrationType();
newPlayerRegistration.Level = "Pro";
newPlayerRegistration.Discipline = "Football";
newPlayerRegistration.Status = "Active";
newPlayerRegistration.OrganisationFIFAId = organisationId;

var newPersonRegistrations = new PersonRegistrationsType();
newPersonRegistrations.PlayerRegistrations.Add(newPlayerRegistration);

var request = new UpdateRegistrationsRequestType(personId,
    oldPersonRegistrations,
    newPersonRegistrations
);

try
{
    var personType = await client.UpdateRegistrations(request, false).ConfigureAwait(false);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the person
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}
3.2.7.3 Remove registrations

Remove player registrations from an existing person with a given ID

const string personId = "105C408";

var person = await client.GetPersonAsync(personId).ConfigureAwait(false);

var registrationsToRemove = new PersonRegistrationsType();
registrationsToRemove.PlayerRegistrations = person.PlayerRegistrations;

var request = new RemoveRegistrationsRequestType(personId, registrationsToRemove);
try
{
    var personType = await client.RemoveRegistrations(request, false).ConfigureAwait(false);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the person
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

Please note that each time an operation succeed, you will receive an object of class PersonType containing the current status of a person with all their registrations. This feature may be used for troubleshooting but also to synchronize the local data with a central DB (ID Directory).

Also note that errors are not thrown if you perform an operation which would result in the object not changing its state. For example, if you want to add a registration for a Football Player, Amateur in France, and such a registration already exists, error will not be thrown and the operation will succeed.

3.2.8 Updating a person

To update a person associated with the specified FIFA ID:

 try
{
    var names = new List<PersonName>();
    names.Add(new PersonName("first name", "last name"));

    var updatedPerson = await client.UpdatePersonAsync("105C40T", names, new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc)).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the person
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

4.Organisation

4.1 Registering an organisation

To register a new organisation:

var organisation = new OrganisationType
{
    Status = "active",
    OrganisationNature = "WorldFederation",
    // fill up all required data according to FIFA Data Standard
};

try
{
    var uniqueFifaId = await client.RegisterOrganisationAsync(organisation).ConfigureAwait(false);
}
catch (AuthenticationException)
{
    // invalid client credentials
}
catch (UnauthorizedException)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaConnectIdException ex)
{
    // some other error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

4.2 Getting organisation data

To get the organisation data associated with the specified FIFA ID use GetOrganisationAsync method. This method will throw FifaOrganisationMergedException when you try to get data for an organisation that has been previously merged and deactivated (refer to section 4.10 Merging organisations). The exception will contain data about requested organisation together with primary organisation id.

try
{
    var uniqueFifaId = "BVGE8TG";
    var organisation = await client.GetOrganisationAsync(uniqueFifaId).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var response = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var response = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the organisation
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaOrganisationMergedException ex)
{
    // requested organisation has been merged and is inactive
    var organisation = ex.RequestedEntity;
    var primaryOrganisationId = ex.PrimaryEntityId;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

4.3 Merging organisations

To merge two organisations into a single one use MergeOrganisationsAsync method available on FifaConnectIdClient. This operation will only work for clubs. In addition you can only merge those that belong to the same member association that you are a member of. As a result of this operation, secondary organisation status will be set to inactive. This affects getting secondary organisation data in the future. Please refer to section 4.2 Getting organisation data. Here is an example how to merge organisations:

try
{
    var organisation = await client.MergeOrganisationsAsync(primaryOrganisationId, secondaryOrganisationId).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find one of specified organisations
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

4.4 Updating an organisation

To update the organisation data use UpdateOrganisationAsync method.

try
{
    var organisationId = "BVGE8TG";
    var organisation = await client.GetOrganisationAsync(organisationId).ConfigureAwait(false);

    // modify data
    organisation.Status = "inactive";
    organisation.Email = "some@other.email";

    var updatedOrganisation = await client.UpdateOrganisationAsync(organisation).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the organisation
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

4.5 Searching for an organisation

To search for an organisation use SearchOrganisation method. It takes SearchOrganisationRequestType as a parameter that aggregates search criteria. It's possible to search by international and local names, parent organisation, organisation nature, and address.

try
{
    var request = new SearchOrganisationRequestType
    {
        InternationalName = "Barcelona",
        OfficialAddress = new SearchAddressType
        {
            Country = "ES",
            Town = "Barcelona"
        },
        NumberOfResults = 5
    };

    var response = await client.SearchOrganisation(request).ConfigureAwait(false);
    var foundOrganisations = response.Organisations;
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}

5. Facility

5.1 Registering a facility

To register a new facility:

var facility = new FacilityType()
{
    Status = "active",
    InternationalName = "Wembley Stadium",
    OrganisationFIFAId = "BVGE8TG"
    // fill up all required data according to FIFA Data Standard
};

try
{
    var uniqueFifaId = await client.RegisterFacilityAsync(facility).ConfigureAwait(false);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaConnectIdException ex)
{
    // some other error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

5.2 Getting facility data

To get the facility data associated with the specified FIFA ID:

try
{
    var uniqueFifaId = "105C40T";
    var facility = await client.GetFacilityAsync(uniqueFifaId).ConfigureAwait(false);
}
catch(AuthenticationException ex)
{
    // invalid client credentials
}
catch(UnauthorizedException ex)
{
    // unauthorized
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the facility
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

5.3 Updating a facility

To update the facility data use UpdateFacilityAsync method.

try
{
    var facilityId = "105C40T";
    var facility = await client.GetFacilityAsync(facilityId).ConfigureAwait(false);

    // set the data to update
    facility.Email = "some@other.email";
    facility.Status = "inactive";

    var updatedFacility = await client.UpdateFacilityAsync(facility).ConfigureAwait(false);
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}
catch (FifaEntityNotFoundException ex)
{
    // could not find the facility
    var operationResponse = ex.HttpOperationResponse;
}
catch (FifaConnectIdException ex)
{
    // some error occurred, see the details
    var operationResponse = ex.HttpOperationResponse;
}

5.4 Searching for a facility

To search for a facility use SearchFacility method. It takes SearchFacilityRequestType as a parameter that aggregates search criteria. It's possible to search by international and local names, parent facility, organisation, and address.

try
{
    var request = new SearchFacilityRequestType
    {
        InternationalName = "Camp Nou",
        OfficialAddress = new SearchAddressType
        {
            Country = "ES",
            Town = "Barcelona"
        },
        NumberOfResults = 5
    };

    var response = await client.SearchFacility(request).ConfigureAwait(false);
    var foundFacilities = response.Facilities;
}
catch (AuthenticationException ex)
{
    // invalid client credentials
    var details = ex.HttpOperationResponse;
}
catch (UnauthorizedException ex)
{
    // unauthorized
    var details = ex.HttpOperationResponse;
}
catch (InvalidClientDataException ex)
{
    // data sent to the service was invalid
    var details = ex.BadRequestResponse;
}

6. Release notes

The following changes were introduced in version 4.1 of the SDK when comparing to version 3.1: