How do I tell if a SagePay UK transaction has been settled via API? - opayo

I'm integrating card payments into a web portal using SagePay UK's Server protocol.
I'd like to know when the transaction has been settled with the bank, so that update the status in the backend. I've looked in MySagePay on the test environment and all our transactions say "Settlement Info: This transaction has not been settled."
Is there a way I can access this settlement info through the Reporting and Admin API? Perhaps one of the fields on either getTransactionDetail or getBatchDetail contain this information - but I can't tell from reading the documentation.

You won't be able to test settlement on the test server - it is a dummy system, hence the settlement processes required to populate the batchid aren't run.
In the live situation, you have two options:
You can use getBatchList to determine which batches of transactions have been sent for settlement (and reported back as settled), then use getBatchDetail to determine which transactions were settled in that batch.
Or you can use getTransactionDetail to establish if there is a batchid for the specific transaction you wish to check.

The getTransactionDetail endpoint returns a lot of transaction data, including the status, on the basis of the transaction-code.
You can use this NuGet package to call, for example, the getTransactionDetail endpoint:
https://www.nuget.org/packages/Joe.Opayo.Admin.Api.Client/1.1.0
The client app allows code like this:
var client = new OpayoAdminApiClient();
var isTest = true;
var request = new OpayoApiRequest(ApiCommandType.GetTransactionDetail, "password", isTest, "user-name", "vendor-name");
var commandSpecificXml = "<vendortxcode>01Jan2010Transaction12345</vendortxcode>";
return await client.ProcessApiCommandAsync<TransactionDetail>(request, commandSpecificXml);

Related

Epic FHR Integrations: Moving from Sandbox to Prod

I've used SMART on FHIR to successfully pull test patient data from Epic's sandbox for a patient-facing app (it's a standalone launch). I'm trying now to pull real patient data from a health system but I keep getting the error when trying to authorize my app: "OAuth2 Error. Something went wrong trying to authorize the client. Please try logging in again."
When I was testing with sandbox data, I used this code as reference and then modified it to work for React. This is code I used to authorize my app:
function pullEpicData() {
FHIR.oauth2.authorize({
'client_id': {Non-Prod Client ID given by Epic},
'scope': 'PATIENT.READ, PATIENT.SEARCH',
'redirect_uri': {my website},
'iss': 'https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/'
})
}
This worked fine.
When I switched to prod mode, I used the following code to try to authorize my app:
function pullEpicData() {
FHIR.oauth2.authorize({
'client_id': {Prod Client ID given by Epic},
'scope': 'PATIENT.READ, PATIENT.SEARCH',
'redirect_uri': {my website},
'iss': 'https://sfd.stanfordmed.org/FHIR/api/FHIR/R4/'
})
}
However, this authorization keeps failing.
I didn't make any other changes to my code. Is there anything else I should be doing when switching from sandbox to prod to make the authorization work properly? I'm not using refresh tokens at the moment. Thanks!
There are two very common causes of this issue:
Your client ID does not qualify for auto-sync.
You didn't wait the ~12 hours for your client ID to sync.
For auto-sync, when you register a client ID, the APIs you select may disqualify you for auto-sync. If you don't qualify for auto-sync, then the healthcare organization you want to connect to just explicitly approve your app before it can be used to connect to their endpoints. There is an indicator near the bottom of the client registration form that indicates if you qualify for auto-sync or not.
Regardless of whether your app qualifies for auto-sync, or was explicitly approved by a health system, any changes to a client can take up to ~12 hours to sync (there is a job that runs every ~12 hours that downloads updates).
Other common OAuth2 connection issues are documented in our Troubleshooting Guide (requires login, but you can signup for an account for free).

How to avoid 'Choose Account' screen with Google Calendar API?

Our app is importing the next 1000 events from a user's Google calendar API. We ran into the problem where nginx would timeout. To get around this I'm putting the pagination data into a session variable and making separate HTTP requests to the API. This works except for one problem: every time we make a new HTTP request the API asks the user to choose which account they want to use (one user with multiple gmail accounts). I would have thought that the pagination data would include account selection but this is apparently not the case. How can I programmatically select the email account within the HTTP request?
You can store it once
public static void setmCredential(GoogleAccountCredential _mCredential) {
mCredential = _mCredential;
mService = new com.google.api.services.calendar.Calendar.Builder(
transport, jsonFactory, mCredential)
.setApplicationName("YourApplicationName")
.build();
}
And then when caliing pass it like this
new MakeRequestTask(AccountCredential.mService).execute();

Should I use a Web API 2.2 custom filter or message handler?

I am building a Web API service which will accept 2 of 4 possible tokens in the header. These tokens are used for different purposes but will all be able to be resolved (using lookup in a DB and other operations) to a couple of key pieces of user data.
Only a limited number of endpoints in my controllers will need to receive this information and so I need to know if I should be building a message handler (I believe this is executed for all requests) or a custom action filter (attached via attributes to the specific endpoints.)
Which method is most appropriate for retrieving data from the request header, using it to retrieve user information and populating the header/request with the retrieved data for the controller to use?
Token is an over-loaded term but if you are using "token" as in security token meant for authentication, you can create an authentication filter. If your tokens are just identifiers using which you pull more data from a data store, action filter is a good choice. As you said, message handlers run for all requests (per-route or global granularity) and may not be a good candidate. However, message handlers run earlier in the pipeline and action filters run just before the action method. So, in future, if any other component in your Web API pipeline needs this data, action filter could be too late. If you know for sure only controllers will ever need this data, action filter is probably the best place, given the granularity they provide.

Correct way to use a Google Apps Marketplace service account to connect to Gmail IMAP and other services

One of the features of our Marketplace app makes use of accessing the user's Gmail account via IMAP. We are using the google-api-java-client and google-oauth-java-client libraries and code similar to this example in the java-gmail-imap project as follows:
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_ID)
.setServiceAccountScopes(Arrays.asList(GMAIL_SCOPE))
.setServiceAccountPrivateKey(PRIVATE_KEY)
.setServiceAccountUser(emailAddress)
.build();
credential.refreshToken();
We are then using code based on the examples at https://code.google.com/p/google-mail-oauth2-tools to make the IMAP connection e.g.
IMAPStore imapStore = OAuth2Authenticator.connectToImap("imap.googlemail.com",
993, emailAddress, credential.getAccessToken(), false);
The majority of the time this appears to work correctly, however we are seeing that for a small but significant number of requests the call to Google made by refreshToken() fails with an HTTP 500 error and an HTML response where the JSON would normally be returned e.g.
<p class="large"><b>500.</b> <ins>That's an error.</ins></p>
<p class="large">The server could not process your request.
<ins>That's all we know.</ins></p>
We were advised by a developer advocate at Google that we refresh tokens are not supported for service accounts and we should be using an approach like in this example.
However, it seems like without the call to refreshToken then accessToken is not populated on the credential object and then this results in a NullPointerException when we call OAuth2Authenticator.connectToImap
From the source for GoogleCredential it did seem like executeRefreshToken() is overridden to handle service accounts i.e. instead of performing a refresh it simply requests a new token, and then this bit of code in Credential then handles populating the access token:
TokenResponse tokenResponse = executeRefreshToken();
if (tokenResponse != null) {
setFromTokenResponse(tokenResponse); ....
We were unsure whether we need to enclose our call to refreshToken() in a retry loop to work around the intermittent 500 errors or whether we need to make other changes to our code to follow the recommended approach for this scenario.
Can anyone advise?
I use the java-gmail-imap example code in production (but it is only used to display an inbox in our University portal, there isn't much interaction that would require me to reuse the same refresh token for instance).
Depending on your usage, I wonder if in your case some kind of throttling is coming into play (I've read in places that Gmail can occasionally throttle access).
Elsewhere I've seen Google APIs talk about making retries using an exponential backoff algorithm.
You have to be a little careful when comparing the usage of OAuth 2.0 with the other Google Service APIs and Gmail. Gmail is special in that it uses XOAUTH2. That said I've seen other Google API's that appear to need the refreshToken call. The documentation is a bit unclear and says things like "Refresh the access token, if necessary" (as you say it doesn't seem to work without this step but I haven't done any experimentation with re-using refresh tokens via credential.setRefreshToken(String refreshToken)).
I'd be interested to hear how you get on.

Creating a local Token cache using the Geneva Framework

Haven't seen many Geneva related questions yet, I have posted this question in the Geneva Forum as well...
I'm working on a scenario where we have a win forms app with a wide installbase, which will be issuing frequent calls to various services hosted by us centrally throughout it's operation.
The services are all using the Geneva Framework and all clients are expected to call our STS first to be issued with a token to allow access to the services.
Out of the box, using the ws2007FederationHttpBinding, the app can be configured to retrieve a token from the STS before each service call, but obviously this is not the most efficient way as we're almost duplicating the effort of calling the services.
Alternatively, I have implemented the code required to retrieve the token "manually" from the app, and then pass the same pre-retrieved token when calling operations on the services (based on the WSTrustClient sample and helpon the forum); that works well and so we do have a solution,but I believeit's not very elegant as it requires building the WCF channel in code, moving away from the wonderful WCF configuration.
I much prefer the ws2007FederationHttpBinding approach where by the client simply calls the service like any other WCF service, without knowing anything about Geneva, and the bindings takes care of the token exchange.
Then someone (Jon Simpson) gave me [what I think is] a great idea - add a service, hosted in the app itself to cache locally retrieved tokens.
The local cache service would implement the same contract as the STS; when receiveing a request it would check to see if a cahced token exists, and if so would return it, otherwise it would call the 'real' STS, retrive a new token, cache it and return it.
The client app could then still use ws2007FederationHttpBinding, but instead of having the STS as the issuer it would have the local cache;
This way I think we can achieve the best of both worlds - caching of tokens without the service-sepcific custom code; our cache should be able to handle tokens for all RPs.
I have created a very simple prototype to see if it works, and - somewhat not surprising unfortunately - I am slightly stuck -
My local service (currently a console app) gets the request, and - first time around - calls the STS to retrieve the token, caches it and succesfully returns it to the client which, subsequently, uses it to call the RP. all works well.
Second time around, however, my local cahce service tries to use the same token again, but the client side fails with a MessageSecurityException -
"Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security."
Is there something preventing the same token to be used more than once? I doubt it because when I reused the token as per the WSTrustClient sample it worked well; what am I missing? is my idea possible? a good one?
Here's the (very basic, at this stage) main code bits of the local cache -
static LocalTokenCache.STS.Trust13IssueResponse cachedResponse = null;
public LocalTokenCache.STS.Trust13IssueResponse Trust13Issue(LocalTokenCache.STS.Trust13IssueRequest request)
{
if (TokenCache.cachedResponse == null)
{
Console.WriteLine("cached token not found, calling STS");
//create proxy for real STS
STS.WSTrust13SyncClient sts = new LocalTokenCache.STS.WSTrust13SyncClient();
//set credentials for sts
sts.ClientCredentials.UserName.UserName = "Yossi";
sts.ClientCredentials.UserName.Password = "p#ssw0rd";
//call issue on real sts
STS.RequestSecurityTokenResponseCollectionType stsResponse = sts.Trust13Issue(request.RequestSecurityToken);
//create result object - this is a container type for the response returned and is what we need to return;
TokenCache.cachedResponse = new LocalTokenCache.STS.Trust13IssueResponse();
//assign sts response to return value...
TokenCache.cachedResponse.RequestSecurityTokenResponseCollection = stsResponse;
}
else
{
}
//...and reutn
return TokenCache.cachedResponse;
This is almost embarrassing, but thanks to Dominick Baier on the forum I no now realise I've missed a huge point (I knew it didn't make sense! honestly! :-) ) -
A token gets retrieved once per service proxy, assuming it hadn't expired, and so all I needed to do is to reuse the same proxy, which I planned to do anyway, but, rather stupidly, didn't on my prototype.
In addition - I found a very interesting sample on the MSDN WCF samples - Durable Issued Token Provider, which, if I understand it correctly, uses a custom endpoint behaviour on the client side to implement token caching, which is very elegant.
I will still look at this approach as we have several services and so we could achieve even more efficiency by re-using the same token between their proxies.
So - two solutions, pretty much infornt of my eyes; hope my stupidity helps someone at some point!
I've provided a complete sample for caching the token here: http://blogs.technet.com/b/meamcs/archive/2011/11/20/caching-sts-security-token-with-an-active-web-client.aspx

Resources