File Coverage

blib/lib/WWW/betfair.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package WWW::betfair;
2 1     1   12996 use strict;
  1         2  
  1         29  
3 1     1   3 use warnings;
  1         2  
  1         23  
4 1     1   268 use WWW::betfair::Template;
  1         1  
  1         20  
5 1     1   264 use WWW::betfair::Request;
  1         3  
  1         23  
6 1     1   424 use WWW::betfair::TypeCheck;
  1         6  
  1         32  
7 1     1   447 use Time::Piece;
  1         5852  
  1         4  
8 1     1   1673 use XML::Simple;
  0            
  0            
9             use Carp qw /croak/;
10             use feature qw/switch/;
11              
12             =head1 NAME
13              
14             WWW::betfair - interact with the betfair API using OO Perl
15              
16             =head1 VERSION
17              
18             Version 1.03
19              
20             =cut
21              
22             our $VERSION = '1.03';
23              
24              
25             =head1 IMPORTANT
26              
27             This module is deprecated and not recommended to be used anymore. Betfair has disabled their old API, and this module no longer works.
28              
29             =head1 WHAT IS BETFAIR?
30              
31             L is a sports betting services provider best known for hosting the largest sports betting exchange in the world. The sports betting exchange works like a marketplace: betfair provides an anonymous platform for individuals to offer and take bets on sports events at a certain price and size; it is the ebay of betting. betfair provides an API for the sports betting exchange which enables users to search for sports events and markets, place and update bets and manage their account by depositing and withdrawing funds.
32              
33             =head1 WHY USE THIS LIBRARY?
34              
35             The betfair API communicates using verbose XML files which contain various bugs and quirks. L makes it easier to use the betfair API by providing a Perl interface which manages the befair session, serializing API calls to betfair into the required XML format and de-serializing and parsing the betfair responses back into Perl data structures. Additionally L provides:
36              
37             =over
38              
39             =item *
40              
41             100% of the free and paid methods of the betfair API
42              
43             =item *
44              
45             Documentation for every method with an example method call and reference to the original betfair documentation
46              
47             =item *
48              
49             Type-checking of arguments before they are sent to betfair
50              
51             =back
52              
53             =head1 WARNING
54              
55             Betting using a software program can have unintended consequences. Check all argument types and values before using the methods in this library. Ensure that you adequately test any method of L before using the method and risking money on it. As per the software license it is provided AS IS and no liability is accepted for any costs or penalties caused by using L.
56              
57             To understand how to use the betfair API it is essential to read the L before using L. The betfair documentation is an excellent reference.
58              
59             =head1 SYNOPSIS
60              
61             L provides an object oriented Perl interface for the betfair v6 API. This library communicates via HTTPS to the betfair servers using XML. To use the API you must have an active and funded account with betfair, and be accessing the API from a location where betfair permits use (e.g. USA based connections are refused, but UK connections are allowed). L provides methods to connect to the betfair exchange, search for market prices place and update bets and manage your betfair account.
62              
63             Example
64              
65             use WWW::betfair;
66             use Data::Dumper;
67              
68             my $betfair = WWW::betfair->new;
69            
70             # login is required before performing any other services
71             if ($betfair->login({username => 'sillymoos', password => 'password123'}) {
72            
73             # check account balance
74             print Dumper($betfair->getAccountFunds);
75              
76             # get a list of all active event types (categories of sporting events e.g. football, tennis, boxing).
77             print Dumper($betfair->getActiveEventTypes);
78              
79             }
80             # login failed print the error message returned by betfair
81             else {
82             print Dumper($betfair->getError);
83             }
84              
85             =head1 NON API METHODS
86              
87             =head2 new
88              
89             Returns a new WWW::betfair object. Does not require any parameters.
90              
91             Example
92              
93             my $betfair = WWW::betfair->new;
94              
95             =cut
96              
97             sub new {
98             my $class = shift;
99             my $self = {
100             xmlsent => undef,
101             xmlreceived => undef,
102             headerError => undef,
103             bodyError => undef,
104             response => {},
105             sessionToken=> undef,
106             };
107             my $obj = bless $self, $class;
108             my $typechecker = WWW::betfair::TypeCheck->new;
109             $obj->{type} = $typechecker;
110             return $obj;
111             }
112              
113             =head2 getError
114              
115             Returns the error message from the betfair API response - this is useful when a request fails. After a successful call API the value returned by getError is 'OK'.
116              
117             Example
118              
119             my $error = $betfair->getError;
120              
121             =cut
122              
123             sub getError {
124             my $self = shift;
125             return $self->{headerError} eq 'OK' ? $self->{bodyError} : $self->{headerError};
126             }
127              
128             =head2 getXMLSent
129              
130             Returns a string of the XML message sent to betfair. This can be useful to inspect if de-bugging a failed API call.
131              
132             Example
133              
134             my $xmlSent = $betfair->getXMLSent;
135              
136             =cut
137              
138             sub getXMLSent {
139             my $self = shift;
140             return $self->{xmlsent};
141             }
142              
143             =head2 getXMLReceived
144              
145             Returns a string of the XML message received from betfair. This can be useful to inspect if de-bugging a failed API call.
146              
147             Example
148              
149             my $xmlReceived = $betfair->getXMLReceived;
150              
151             =cut
152              
153             sub getXMLReceived {
154             my $self = shift;
155             return $self->{xmlreceived};
156             }
157              
158             =head2 getHashReceived
159              
160             Returns a Perl data structure consisting of the entire de-serialized betfair XML response. This can be useful to inspect if de-bugging a failed API call and easier to read than the raw XML message, especially if used in conjunction with L.
161              
162             Example
163              
164             my $hashReceived = $betfair->getHashReceived;
165              
166             =cut
167              
168             sub getHashReceived {
169             my $self = shift;
170             return $self->{response};
171             }
172              
173             =head1 GENERAL API METHODS
174              
175             =head2 login
176              
177             Authenticates the user and starts a session with betfair. This is required before any other methods can be used. Returns 1 on success and 0 on failure. If login fails and you are sure that you are using the correct the credentials, check the $betfair->{error} attribute. A common reason for failure on login is not having a funded betfair account. To resolve this, simply make a deposit into your betfair account and the login should work. See L for details. Required arguments:
178              
179             =over
180              
181             =item *
182              
183             username: string of your betfair username
184              
185             =item *
186              
187             password: string of your betfair password
188              
189             =item *
190              
191             productID: integer that indicates the API product to be used (optional). This defaults to 82 (the free personal API). Provide this argument if using a commercial version of the betfair API.
192              
193             =back
194              
195             Example
196              
197             $betfair->login({
198             username => 'sillymoos',
199             password => 'password123',
200             });
201              
202             =cut
203              
204             sub login {
205             my ($self, $args) = @_;
206             my $paramChecks = {
207             username => ['username', 1],
208             password => ['password', 1],
209             productId => ['int', 0],
210             };
211             return 0 unless $self->_checkParams($paramChecks, $args);
212             my $params = {
213             username => $args->{username},
214             password => $args->{password},
215             productId => $args->{productId} || 82,
216             locationId => 0,
217             ipAddress => 0,
218             vendorId => 0,
219             exchangeId => 3,
220             };
221             return $self->_doRequest('login', $params);
222             }
223              
224             =head2 keepAlive
225              
226             Refreshes the current session with betfair. Returns 1 on success and 0 on failure. See L for details. Does not require any parameters. This method is not normally required as a session expires after 24 hours of inactivity.
227              
228             Example
229              
230             $betfair->keepAlive;
231              
232             =cut
233              
234             sub keepAlive {
235             my $self = shift;
236             return $self->_doRequest('keepAlive', {exchangeId => 3});
237             }
238              
239             =head2 logout
240              
241             Closes the current session with betfair. Returns 1 on success and 0 on failure. See L for details. Does not require any parameters.
242              
243             Example
244              
245             $betfair->logout;
246              
247             =cut
248              
249             sub logout {
250             my $self = shift;
251             if ($self->_doRequest('logout', {exchangeId => 3})) {
252             # check body error message, different to header error
253             my $self->{error}
254             = $self->{response}->{'soap:Body'}->{'n:logoutResponse'}->{'n:Result'}->{'errorCode'}->{content};
255             return 1 if $self->{error} eq 'OK';
256             }
257             return 0;
258             }
259              
260             =head1 READ ONLY BETTING API METHODS
261              
262             =head2 convertCurrency
263              
264             Returns the betfair converted amount of currency see L for details. Requires a hashref with the following parameters:
265              
266             =over
267              
268             =item *
269              
270             amount: this is the decimal amount of base currency to convert.
271              
272             =item *
273              
274             fromCurrency : this is the base currency to convert from.
275              
276             =item *
277              
278             toCurrency : this is the target currency to convert to.
279              
280             =back
281              
282             Example
283              
284             $betfair->convertCurrency({ amount => 5,
285             fromCurrency => 'GBP',
286             toCurrency => 'USD',
287             });
288              
289             =cut
290              
291             sub convertCurrency {
292             my ($self, $args) = @_;
293             my $checkParams = {
294             amount => ['decimal', 1],
295             fromCurrency => ['string', 1],
296             toCurrency => ['string', 1],
297             };
298             $args->{exchangeId} = 3;
299             return 0 unless $self->_checkParams($checkParams, $args);
300             if ($self->_doRequest('convertCurrency', $args) ) {
301             return { convertedAmount =>
302             $self->{response}->{'soap:Body'}->{'n:convertCurrencyResponse'}->{'n:Result'}->{'convertedAmount'}->{content}
303             };
304             }
305             return 0;
306             }
307              
308             =head2 getActiveEventTypes
309              
310             Returns an array of hashes of active event types or 0 on failure. See L for details. Does not require any parameters.
311              
312             Example
313              
314             my $activeEventTypes = $betfair->getActiveEventTypes;
315              
316             =cut
317              
318             sub getActiveEventTypes {
319             my $self = shift;
320             my $active_event_types =[];
321             if ($self->_doRequest('getActiveEventTypes', {exchangeId => 3}) ) {
322             foreach (@{$self->{response}->{'soap:Body'}->{'n:getActiveEventTypesResponse'}->{'n:Result'}->{'eventTypeItems'}->{'n2:EventType'}}) {
323             push(@{$active_event_types},{
324             name => $_->{'name'}->{content},
325             id => $_->{'id'}->{content},
326             exchangeId => $_->{'exchangeId'}->{content},
327             nextMarketId => $_->{'nextMarketId'}->{content},
328             });
329             }
330             return $active_event_types;
331             }
332             return 0;
333             }
334              
335             =head2 getAllCurrencies
336              
337             Returns an arrayref of currency codes and the betfair GBP exchange rate. See L. Requires no parameters.
338              
339             Example
340              
341             $betfair->getAllCurrencies;
342              
343             =cut
344              
345             sub getAllCurrencies {
346             my $self = shift;
347             my $currencies =[];
348             if ($self->_doRequest('getAllCurrencies', {exchangeId => 3}) ) {
349             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllCurrenciesResponse'}->{'n:Result'}->{'currencyItems'}->{'n2:Currency'}}) {
350             push(@{$currencies},{
351             currencyCode => $_->{'currencyCode'}->{content},
352             rateGBP => $_->{'rateGBP'}->{content},
353             });
354             }
355             return $currencies;
356             }
357             return 0;
358             }
359              
360             =head2 getAllCurrenciesV2
361              
362             Returns an arrayref of currency codes, the betfair GBP exchange rate and staking sizes for the currency. See L. Requires no parameters.
363              
364             Example
365              
366             $betfair->getAllCurrenciesV2;
367              
368             =cut
369              
370             sub getAllCurrenciesV2 {
371             my $self = shift;
372             my $currenciesV2 =[];
373             if ($self->_doRequest('getAllCurrenciesV2', {exchangeId => 3}) ) {
374             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllCurrenciesV2Response'}->{'n:Result'}->{'currencyItems'}->{'n2:CurrencyV2'}}) {
375             push(@{$currenciesV2},{
376             currencyCode => $_->{'currencyCode'}->{content},
377             rateGBP => $_->{'rateGBP'}->{content},
378             minimumStake => $_->{'minimumStake'}->{content},
379             minimumRangeStake => $_->{'minimumRangeStake'}->{content},
380             minimumBSPLayLiability => $_->{'minimumBSPLayLiability'}->{content},
381             });
382             }
383             return $currenciesV2;
384             }
385             return 0;
386             }
387              
388             =head2 getAllEventTypes
389              
390             Returns an array of hashes of all event types or 0 on failure. See L for details. Does not require any parameters.
391              
392             Example
393              
394             my $allEventTypes = $betfair->getAllEventTypes;
395              
396             =cut
397              
398             sub getAllEventTypes {
399             my $self = shift;
400             if ($self->_doRequest('getAllEventTypes', {exchangeId => 3})) {
401             my $all_event_types = [];
402             foreach (@{$self->{response}->{'soap:Body'}->{'n:getAllEventTypesResponse'}->{'n:Result'}->{'eventTypeItems'}->{'n2:EventType'} }) {
403             push(@{$all_event_types},{
404             name => $_->{'name'}->{content},
405             id => $_->{'id'}->{content},
406             exchangeId => $_->{'exchangeId'}->{content},
407             nextMarketId => $_->{'nextMarketId'}->{content},
408             });
409             }
410             return $all_event_types;
411             }
412             return 0;
413             }
414              
415             =head2 getAllMarkets
416              
417             Returns an array of hashes of all markets or 0 on failure. See L for details. Requires a hashref with the following parameters:
418              
419             =over
420              
421             =item *
422              
423             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
424              
425             =back
426              
427             Example
428              
429             my $allMarkets = $betfair->getAllMarkets({exchangeId => 1});
430              
431             =cut
432              
433             sub getAllMarkets {
434             my ($self, $args) = @_;
435             my $checkParams = {exchangeId => ['exchangeId', 1]};
436             return 0 unless $self->_checkParams($checkParams, $args);
437             if ($self->_doRequest('getAllMarkets', $args)) {
438             my $all_markets = [];
439             foreach (split /:/, $self->{response}->{'soap:Body'}->{'n:getAllMarketsResponse'}->{'n:Result'}->{'marketData'}->{content}) {
440             next unless $_;
441             my @market = split /~/;
442             push @{$all_markets}, {
443             marketId => $market[0],
444             marketName => $market[1],
445             marketType => $market[2],
446             marketStatus => $market[3],
447             marketDate => $market[4],
448             menuPath => $market[5],
449             eventHierarchy => $market[6],
450             betDelay => $market[7],
451             exchangeId => $market[8],
452             iso3CountryCode => $market[9],
453             lastRefresh => $market[10],
454             numberOfRunners => $market[11],
455             numberOfWinners => $market[12],
456             totalMatchedAmount => $market[13],
457             bspMarket => $market[14],
458             turningInPlay => $market[15],
459             };
460             }
461             return $all_markets;
462             }
463             return 0;
464             }
465              
466             =head2 getBet
467              
468             Returns a hashref of betfair's bet response, including an array of all matches to a bet. See L for details. Requires a hashref with the following argument:
469              
470             =over
471              
472             =item *
473              
474             betId - the betId integer of the bet to retrieve data about.
475              
476             =item *
477              
478             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
479              
480             =back
481              
482             Example
483              
484             my $bet = $betfair->getBet({betId => 123456789
485             exchangeId => 1,
486             });
487              
488             =cut
489              
490             sub getBet {
491             my ($self, $args) = @_;
492             my $checkParams = { betId => ['int', 1],
493             exchangeId => ['exchangeId', 1],
494             };
495             return 0 unless $self->_checkParams($checkParams, $args);
496             if ($self->_doRequest('getBet', $args)) {
497             my $response = $self->{response}->{'soap:Body'}->{'n:getBetResponse'}->{'n:Result'}->{bet};
498             my $bet = {
499             asianLineId => $response->{asianLineId}->{content},
500             avgPrice => $response->{avgPrice}->{content},
501             betCategoryType => $response->{betCategoryType}->{content},
502             betId => $response->{betId}->{content},
503             betPersistenceType => $response->{betPersistenceType}->{content},
504             betStatus => $response->{betStatus}->{content},
505             betType => $response->{betType}->{content},
506             bspLiability => $response->{bspLiability}->{content},
507             cancelledDate => $response->{cancelledDate}->{content},
508             executedBy => $response->{executedBy}->{content},
509             fullMarketName => $response->{fullMarketName}->{content},
510             handicap => $response->{handicap}->{content},
511             lapsedDate => $response->{lapsedDate}->{content},
512             marketId => $response->{marketId}->{content},
513             marketName => $response->{marketName}->{content},
514             marketType => $response->{marketType}->{content},
515             marketTypeVariant => $response->{marketTypeVariant}->{content},
516             matchedDate => $response->{matchedDate}->{content},
517             matchedSize => $response->{matchedSize}->{content},
518             matches => [],
519             placedDate => $response->{placedDate}->{content},
520             price => $response->{price}->{content},
521             profitAndLoss => $response->{profitAndLoss}->{content},
522             remainingSize => $response->{remainingSize}->{content},
523             requestedSize => $response->{requestedSize}->{content},
524             selectionId => $response->{selectionId}->{content},
525             selectionName => $response->{selectionName}->{content},
526             settledDate => $response->{settledDate}->{content},
527             voidedDate => $response->{voidedDate}->{content},
528             };
529             my $matches = $self->_forceArray($response->{matches}->{'n2:Match'});
530             foreach my $match (@{$matches}){
531             push @{$bet->{matches}}, {
532             betStatus => $match->{betStatus}->{content},
533             matchedDate => $match->{matchedDate}->{content},
534             priceMatched => $match->{priceMatched}->{content},
535             profitLoss => $match->{profitLoss}->{content},
536             settledDate => $match->{settledDate}->{content},
537             sizeMatched => $match->{sizeMatched}->{content},
538             transactionId => $match->{transactionId}->{content},
539             voidedDate => $match->{voidedDate}->{content},
540             };
541             }
542             return $bet;
543             }
544             return 0;
545             }
546              
547             =head2 getBetHistory
548              
549             Returns an arrayref of hashrefs of bets. See L for details. Requires a hashref with the following parameters:
550              
551             =over
552              
553             =item *
554              
555             betTypesIncluded : string of a valid BetStatusEnum type as defined by betfair (see L)
556              
557             =item *
558              
559             detailed : boolean string e.g. ('true' or 'false') indicating whether or not to include the details of all matches per bet.
560              
561             =item *
562              
563             eventTypeIds : an arrayref of integers that represent the betfair eventTypeIds. (e.g. [1, 6] would be football and boxing). This is not mandatory if the betTypesIncluded parameter equals 'M' or 'U'.
564              
565             =item *
566              
567             marketId : an integer representing the betfair marketId (optional).
568              
569             =item *
570              
571             marketTypesIncluded : arrayref of strings of the betfair marketTypesIncluded enum. See L for details.
572              
573             =item *
574              
575             placedDateFrom : string date for which to return records on or after this date (a string in the XML datetime format see example).
576              
577             =item *
578              
579             placedDateTo : string date for which to return records on or before this date (a string in the XML datetime format see example).
580              
581             =item *
582              
583             recordCount : integer representing the maximum number of records to retrieve (must be between 1 and 100).
584              
585             =item *
586              
587             sortBetsBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
588              
589             =item *
590              
591             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
592              
593             =item *
594              
595             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
596              
597             =back
598              
599             Example
600              
601             my $betHistory = $betfair->getBetHistory({
602             betTypesIncluded => 'M',
603             detailed => 'false',
604             eventTypeIds => [6],
605             marketTypesIncluded => ['O', 'L', 'R'],
606             placedDateFrom => '2013-01-01T00:00:00.000Z',
607             placedDateTo => '2013-06-16T00:00:00.000Z',
608             recordCount => 100,
609             sortBetsBy => 'PLACED_DATE',
610             startRecord => 0,
611             exchangeId => 1,
612             });
613              
614             =cut
615              
616             sub getBetHistory {
617             my ($self, $args) = @_;
618             my $checkParams = {
619             betTypesIncluded => ['betStatusEnum', 1],
620             detailed => ['boolean', 1],
621             eventTypeIds => ['arrayInt', 1],
622             sortBetsBy => ['betsOrderByEnum', 1],
623             recordCount => ['int', 1,],
624             startRecord => ['int', 1],
625             placedDateTo => ['date', 1],
626             placedDateFrom => ['date', 1],
627             marketTypesIncluded => ['arrayMarketTypeEnum', 1],
628             marketId => ['int', 0],
629             exchangeId => ['exchangeId', 1],
630             };
631             # eventTypeIds is not mandatory if betTypesIncluded is 'M' or 'U'
632             $checkParams->{eventTypeIds}->[1] = 0 if grep{/$args->{betTypesIncluded}/} qw/M U/;
633              
634             # marketId is mandatory if betTypesIncluded is 'S', 'C', or 'V'
635             $checkParams->{marketId}->[1] = 1 if grep{/$args->betTypesIncluded/} qw/S C V/;
636            
637             return 0 unless $self->_checkParams($checkParams, $args);
638              
639             # make eventTypeIds an array of int
640             my @eventTypeIds = $args->{eventTypeIds};
641             delete $args->{eventTypeIds};
642             $args->{eventTypeIds}->{'int'} = \@eventTypeIds;
643              
644             # make marketTypesIncluded an array of marketTypeEnum
645             my @marketTypes = $args->{marketTypesIncluded};
646             delete $args->{marketTypesIncluded};
647             $args->{marketTypesIncluded}->{'MarketTypeEnum'} = \@marketTypes;
648              
649             if ($self->_doRequest('getBetHistory', $args) ) {
650             my $response = $self->_forceArray(
651             $self->{response}->{'soap:Body'}->{'n:getBetHistoryResponse'}->{'n:Result'}->{'betHistoryItems'}->{'n2:Bet'});
652             my $betHistory = [];
653             foreach (@{$response}) {
654             my $bet = {
655             asianLineId => $_->{asianLineId}->{content},
656             avgPrice => $_->{avgPrice}->{content},
657             betCategoryType => $_->{betCategoryType}->{content},
658             betId => $_->{betId}->{content},
659             betPersistenceType => $_->{betPersistenceType}->{content},
660             betStatus => $_->{betStatus}->{content},
661             betType => $_->{betType}->{content},
662             bspLiability => $_->{bspLiability}->{content},
663             cancelledDate => $_->{cancelledDate}->{content},
664             fullMarketName => $_->{fullMarketName}->{content},
665             handicap => $_->{handicap}->{content},
666             lapsedDate => $_->{lapsedDate}->{content},
667             marketId => $_->{marketId}->{content},
668             marketName => $_->{marketName}->{content},
669             marketType => $_->{marketType}->{content},
670             marketTypeVariant => $_->{marketTypeVariant}->{content},
671             matchedDate => $_->{matchedDate}->{content},
672             matchedSize => $_->{matchedSize}->{content},
673             matches => [],
674             placedDate => $_->{placedDate}->{content},
675             price => $_->{price}->{content},
676             profitAndLoss => $_->{profitAndLoss}->{content},
677             remainingSize => $_->{remainingSize}->{content},
678             requestedSize => $_->{requestedSize}->{content},
679             selectionId => $_->{selectionId}->{content},
680             selectionName => $_->{selectionName}->{content},
681             settledDate => $_->{settledDate}->{content},
682             voidedDate => $_->{voidedDate}->{content},
683             };
684             my $matches = $self->_forceArray($_->{matches}->{'n2:Match'});
685             foreach my $match (@{$matches}){
686             push @{$bet->{matches}}, {
687             betStatus => $match->{betStatus}->{content},
688             matchedDate => $match->{matchedDate}->{content},
689             priceMatched => $match->{priceMatched}->{content},
690             profitLoss => $match->{profitLoss}->{content},
691             settledDate => $match->{settledDate}->{content},
692             sizeMatched => $match->{sizeMatched}->{content},
693             transactionId => $match->{transactionId}->{content},
694             voidedDate => $match->{voidedDate}->{content},
695             };
696             }
697             push @{$betHistory}, $bet;
698             }
699             return $betHistory;
700             }
701             return 0;
702             }
703              
704             =head2 getBetLite
705              
706             Returns a hashref of bet information. See L for details. Requires a hashref with the following key pair/s:
707              
708             =over
709              
710             =item *
711              
712             betId : integer representing the betfair id for the bet to retrieve data about.
713              
714             =item *
715              
716             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
717              
718             =back
719              
720             Example
721              
722             my $betData = $betfair->getBetLite({betId => 123456789
723             exchangeId => 2,
724             });
725              
726             =cut
727              
728             sub getBetLite {
729             my ($self, $args) = @_;
730             my $checkParams = { betId => ['int', 1],
731             exchangeId => ['exchangeId', 1],
732             };
733             return 0 unless $self->_checkParams($checkParams, $args);
734             if ($self->_doRequest('getBetLite', $args)) {
735             my $response = $self->{response}->{'soap:Body'}->{'n:getBetLiteResponse'}->{'n:Result'}->{'betLite'};
736             return {
737             betCategoryType => $response->{betCategoryType}->{content},
738             betId => $response->{betId}->{content},
739             betPersistenceType => $response->{betPersistenceType}->{content},
740             betStatus => $response->{betStatus}->{content},
741             bspLiability => $response->{bspLiability}->{content},
742             marketId => $response->{marketId}->{content},
743             matchedSize => $response->{matchedSize}->{content},
744             remainingSize => $response->{remainingSize}->{content},
745             };
746             }
747             return 0;
748             }
749              
750              
751             =head2 getBetMatchesLite
752              
753             Returns an arrayref of hashrefs of matched bet information. See L for details. Requires a hashref with the following key pair/s:
754              
755             =over
756              
757             =item *
758              
759             betId : integer representing the betfair id for the bet to retrieve data about.
760              
761             =item *
762              
763             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
764              
765             =back
766              
767             Example
768              
769             my $betData = $betfair->getBetMatchesLite({ betId => 123456789
770             exchangeId => 1,
771             });
772              
773             =cut
774              
775             sub getBetMatchesLite {
776             my ($self, $args) = @_;
777             my $checkParams = { betId => ['int', 1],
778             exchangeId => ['exchangeId', 0],
779             };
780             return 0 unless $self->_checkParams($checkParams, $args);
781             if ($self->_doRequest('getBetMatchesLite', $args)) {
782             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getBetMatchesLiteResponse'}->{'n:Result'}->{matchLites}->{'n2:MatchLite'});
783             my $matchedBets = [];
784             foreach (@{$response}) {
785             push @{$matchedBets}, {
786             betStatus => $_->{betStatus}->{content},
787             matchedDate => $_->{matchedDate}->{content},
788             priceMatched => $_->{priceMatched}->{content},
789             sizeMatched => $_->{sizeMatched}->{content},
790             transactionId => $_->{transactionId}->{content},
791             };
792             }
793             return $matchedBets;
794             }
795             return 0;
796             }
797              
798             =head2 getCompleteMarketPricesCompressed
799              
800             Returns a hashref of market data including an arrayhashref of individual selection prices data. See L for details. Note that this method de-serializes the compressed string returned by the betfair method into a Perl data structure. Requires:
801              
802             =over
803              
804             =item *
805              
806             marketId : integer representing the betfair market id.
807              
808             =item *
809              
810             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
811              
812             =item *
813              
814             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
815              
816             =back
817              
818             Example
819              
820             my $marketPriceData = $betfair->getCompleteMarketPricesCompressed({ marketId => 123456789,
821             exchangeId => 2,
822             });
823              
824             =cut
825              
826             sub getCompleteMarketPricesCompressed {
827             my ($self, $args) = @_;
828             my $checkParams = {
829             marketId => ['int', 1],
830             currencyCode => ['currencyCode', 0],
831             exchangeId => ['exchangeId', 1],
832             };
833             return 0 unless $self->_checkParams($checkParams, $args);
834             if ($self->_doRequest('getCompleteMarketPricesCompressed', $args)) {
835             my $response = $self->{response}->{'soap:Body'}->{'n:getCompleteMarketPricesCompressedResponse'}->{'n:Result'}->{'completeMarketPrices'}->{content};
836             my @fields = split /:/, $response;
837             #109799180~0~;name,timeRemoved,reductionFactor;
838             my $idAndRemovedRunners = shift @fields; # not used yet
839             my $selections = [];
840             foreach my $selection (@fields) {
841             my @selectionFields = split /\|/, $selection;
842             my @selectionData = split /~/, shift @selectionFields;
843             my $prices = [];
844             next unless $selectionFields[0];
845             my @selectionPrices = split /~/, $selectionFields[0];
846             while (@selectionPrices) {
847             push @{$prices}, {
848             price => shift @selectionPrices,
849             back_amount => shift @selectionPrices,
850             lay_amount => shift @selectionPrices,
851             bsp_back_amount => shift @selectionPrices,
852             bsp_lay_amount => shift @selectionPrices,
853             };
854             }
855             push @{$selections}, {
856             prices => $prices,
857             selectionId => $selectionData[0],
858             orderIndex => $selectionData[1],
859             totalMatched => $selectionData[2],
860             lastPriceMatched => $selectionData[3],
861             asianHandicap => $selectionData[4],
862             reductionFactor => $selectionData[5],
863             vacant => $selectionData[6],
864             asianLineId => $selectionData[7],
865             farPriceSp => $selectionData[8],
866             nearPriceSp => $selectionData[9],
867             actualPriceSp => $selectionData[10],
868             };
869             }
870             return { marketId => $args->{marketId},
871             selections => $selections,
872             };
873             }
874             return 0;
875             }
876              
877             =head2 getCurrentBets
878              
879             Returns an arrayref of hashrefs of current bets or 0 on failure. See L for details. Requires a hashref with the following parameters:
880              
881             =over
882              
883             =item *
884              
885             betStatus : string of a valid BetStatus enum type as defined by betfair see L for details.
886              
887             =item *
888              
889             detailed : string of either true or false
890              
891             =item *
892              
893             orderBy : string of a valid BetsOrderByEnum types as defined by betfair (see L)
894              
895             =item *
896              
897             recordCount : integer of the maximum number of records to return
898              
899             =item *
900              
901             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
902              
903             =item *
904              
905             noTotalRecordCount : string of either true or false
906              
907             =item *
908              
909             marketId : integer of the betfair market id for which current bets are required (optional)
910              
911             =item *
912              
913             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
914              
915             =back
916              
917             Example
918              
919             my $bets = $betfair->getCurrentBets({
920             betStatus => 'M',
921             detailed => 'false',
922             orderBy => 'PLACED_DATE',
923             recordCount => 100,
924             startRecord => 0,
925             noTotalRecordCount => 'true',
926             exchangeId => 1,
927             });
928              
929             =cut
930              
931             sub getCurrentBets {
932             my ($self, $args) = @_;
933             my $checkParams = {
934             betStatus => ['betStatusEnum', 1],
935             detailed => ['boolean', 1],
936             orderBy => ['betsOrderByEnum', 1],
937             recordCount => ['int', 1,],
938             startRecord => ['int', 1],
939             noTotalRecordCount => ['boolean', 1],
940             marketId => ['int',0],
941             exchangeId => ['exchangeId', 1],
942             };
943             return 0 unless $self->_checkParams($checkParams, $args);
944             if ($self->_doRequest('getCurrentBets', $args) ) {
945             my $response = $self->_forceArray(
946             $self->{response}->{'soap:Body'}->{'n:getCurrentBetsResponse'}->{'n:Result'}->{'bets'}->{'n2:Bet'});
947             my $current_bets = [];
948             foreach (@{$response}) {
949             my $bet = {
950             asianLineId => $_->{asianLineId}->{content},
951             avgPrice => $_->{avgPrice}->{content},
952             betCategoryType => $_->{betCategoryType}->{content},
953             betId => $_->{betId}->{content},
954             betPersistenceType => $_->{betPersistenceType}->{content},
955             betStatus => $_->{betStatus}->{content},
956             betType => $_->{betType}->{content},
957             bspLiability => $_->{bspLiability}->{content},
958             cancelledDate => $_->{cancelledDate}->{content},
959             fullMarketName => $_->{fullMarketName}->{content},
960             handicap => $_->{handicap}->{content},
961             lapsedDate => $_->{lapsedDate}->{content},
962             marketId => $_->{marketId}->{content},
963             marketName => $_->{marketName}->{content},
964             marketType => $_->{marketType}->{content},
965             marketTypeVariant => $_->{marketTypeVariant}->{content},
966             matchedDate => $_->{matchedDate}->{content},
967             matchedSize => $_->{matchedSize}->{content},
968             matches => [],
969             placedDate => $_->{placedDate}->{content},
970             price => $_->{price}->{content},
971             profitAndLoss => $_->{profitAndLoss}->{content},
972             remainingSize => $_->{remainingSize}->{content},
973             requestedSize => $_->{requestedSize}->{content},
974             selectionId => $_->{selectionId}->{content},
975             selectionName => $_->{selectionName}->{content},
976             settledDate => $_->{settledDate}->{content},
977             voidedDate => $_->{voidedDate}->{content},
978             };
979             my $matches = $self->_forceArray($_->{matches}->{'n2:Match'});
980             foreach my $match (@{$matches}){
981             push @{$bet->{matches}}, {
982             betStatus => $match->{betStatus}->{content},
983             matchedDate => $match->{matchedDate}->{content},
984             priceMatched => $match->{priceMatched}->{content},
985             profitLoss => $match->{profitLoss}->{content},
986             settledDate => $match->{settledDate}->{content},
987             sizeMatched => $match->{sizeMatched}->{content},
988             transactionId => $match->{transactionId}->{content},
989             voidedDate => $match->{voidedDate}->{content},
990             };
991             }
992             push @{$current_bets}, $bet;
993             }
994             return $current_bets;
995             }
996             return 0;
997             }
998              
999             =head2 getCurrentBetsLite
1000              
1001             Returns an arrayref of hashrefs of current bets for a single market or the entire exchange. See L for details. Requires a hashref with the following parameters:
1002              
1003             =over
1004              
1005             =item *
1006              
1007             betStatus : string of a valid BetStatus enum type as defined by betfair see L for details.
1008              
1009             =item *
1010              
1011             orderBy : string of a valid BetsOrderByEnum types as defined by betfair (see L)
1012              
1013             =item *
1014              
1015             recordCount : integer of the maximum number of records to return
1016              
1017             =item *
1018              
1019             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1020              
1021             =item *
1022              
1023             noTotalRecordCount : string of either 'true' or 'false' to return a total record count
1024              
1025             =item *
1026              
1027             marketId : integer of the betfair market id for which current bets are required (optional)
1028              
1029             =item *
1030              
1031             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1032              
1033             =back
1034              
1035             Example
1036              
1037             my $bets = $betfair->getCurrentBetsLite({
1038             betStatus => 'M',
1039             orderBy => 'PLACED_DATE',
1040             recordCount => 100,
1041             startRecord => 0,
1042             noTotalRecordCount => 'true',
1043             exchangeId => 1,
1044             });
1045              
1046             =cut
1047              
1048             sub getCurrentBetsLite {
1049             my ($self, $args) = @_;
1050             my $checkParams = {
1051             betStatus => ['betStatusEnum', 1],
1052             orderBy => ['betsOrderByEnum', 1],
1053             recordCount => ['int', 1,],
1054             startRecord => ['int', 1],
1055             noTotalRecordCount => ['boolean', 1],
1056             marketId => ['int', 0],
1057             exchangeId => ['exchangeId', 1],
1058             };
1059             return 0 unless $self->_checkParams($checkParams, $args);
1060             if ($self->_doRequest('getCurrentBetsLite', $args) ) {
1061             my $response = $self->_forceArray(
1062             $self->{response}->{'soap:Body'}->{'n:getCurrentBetsLiteResponse'}->{'n:Result'}->{'betLites'}->{'n2:BetLite'});
1063             my $current_bets = [];
1064             foreach (@{$response}) {
1065             push @{$current_bets}, {
1066             betCategoryType => $_->{betCategoryType}->{content},
1067             betId => $_->{betId}->{content},
1068             betPersistenceType => $_->{betPersistenceType}->{content},
1069             betStatus => $_->{betStatus}->{content},
1070             bspLiability => $_->{bspLiability}->{content},
1071             marketId => $_->{marketId}->{content},
1072             matchedSize => $_->{matchedSize}->{content},
1073             remainingSize => $_->{remainingSize}->{content},
1074             };
1075             }
1076             return $current_bets;
1077             }
1078             return 0;
1079             }
1080              
1081             =head2 getDetailAvailableMktDepth
1082              
1083             Returns an arrayref of current back and lay offers in a market for a specific selection. See L for details. Requires a hashref with the following arguments:
1084              
1085             =over
1086              
1087             =item *
1088              
1089             marketId : integer representing the betfair market id to return the market prices for.
1090              
1091             =item *
1092              
1093             selectionId : integer representing the betfair selection id to return market prices for.
1094              
1095             =item *
1096              
1097             asianLineId : integer representing the betfair asian line id of the market - only required if the market is an asian line market (optional).
1098              
1099             =item *
1100              
1101             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1102              
1103             =item *
1104              
1105             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1106              
1107             =back
1108              
1109             Example
1110              
1111             my $selectionPrices = $betfair->getDetailAvailableMktDepth({marketId => 123456789,
1112             selectionId => 987654321,
1113             exchangeId => 1,
1114             });
1115              
1116             =cut
1117              
1118             sub getDetailAvailableMktDepth {
1119             my ($self, $args) = @_;
1120             my $checkParams = { marketId => ['int', 1],
1121             selectionId => ['int', 1],
1122             asianLineId => ['int', 0],
1123             exchangeId => ['exchangeId', 1],
1124             currencyCode=> ['currencyCode', 0],
1125             };
1126             return 0 unless $self->_checkParams($checkParams, $args);
1127             if ($self->_doRequest('getDetailAvailableMktDepth', $args)) {
1128             my $response = $self->_forceArray(
1129             $self->{response}->{'soap:Body'}->{'n:getDetailAvailableMktDepthResponse'}->{'n:Result'}->{'priceItems'}->{'n2:AvailabilityInfo'});
1130             my $marketPrices = [];
1131             foreach (@{$response}){
1132             push @{$marketPrices}, {
1133             odds => $_->{odds}->{content},
1134             totalAvailableBackAmount=> $_->{totalAvailableBackAmount}->{content},
1135             totalAvailableLayAmount => $_->{totalAvailableLayAmount}->{content},
1136             totalBspBackAmount => $_->{totalBspBackAmount}->{content},
1137             totalBspLayAmount => $_->{totalBspLayAmount}->{content},
1138             };
1139             }
1140             return $marketPrices;
1141             }
1142             return 0;
1143             }
1144              
1145             =head2 getEvents
1146              
1147             Returns an array of hashes of events / markets or 0 on failure. See L for details. Requires:
1148              
1149             =over
1150              
1151             =item *
1152              
1153             eventParentId : an integer which is the betfair event id of the parent event
1154              
1155             =back
1156              
1157             Example
1158              
1159             # betfair event id of tennis is 14
1160             my $tennisEvents = $betfair->getEvents({eventParentId => 14});
1161              
1162             =cut
1163              
1164             sub getEvents {
1165             my ($self, $args) = @_;
1166             my $checkParams = { eventParentId => ['int', 1] };
1167             return 0 unless $self->_checkParams($checkParams, $args);
1168             $args->{exchangeId} = 3;
1169             if ($self->_doRequest('getEvents', $args)) {
1170             my $event_response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getEventsResponse'}->{'n:Result'}->{'eventItems'}->{'n2:BFEvent'});
1171             my $events;
1172             foreach (@{$event_response}) {
1173             next unless defined($_->{eventId}->{content});
1174             push @{$events->{events}}, {
1175             eventId => $_->{eventId}->{content},
1176             eventName => $_->{eventName}->{content},
1177             menuLevel => $_->{menuLevel}->{content},
1178             orderIndex => $_->{orderIndex}->{content},
1179             eventTypeId => $_->{eventTypeId}->{content},
1180             startTime => $_->{startTime}->{content},
1181             timezone => $_->{timezone}->{content},
1182             };
1183             }
1184             my $market_response = $self->_forceArray(
1185             $self->{response}->{'soap:Body'}->{'n:getEventsResponse'}->{'n:Result'}->{'marketItems'}->{'n2:MarketSummary'});
1186             foreach (@{$market_response}) {
1187             next unless defined($_->{marketId}->{content});
1188             push @{$events->{markets}}, {
1189             marketId => $_->{marketId}->{content},
1190             marketName => $_->{marketName}->{content},
1191             menuLevel => $_->{menuLevel}->{content},
1192             orderIndex => $_->{orderIndex}->{content},
1193             marketType => $_->{marketType}->{content},
1194             marketTypeVariant => $_->{marketTypeVariant}->{content},
1195             exchangeId => $_->{exchangeId}->{content},
1196             venue => $_->{venue}->{content},
1197             betDelay => $_->{betDelay}->{content},
1198             numberOfWinners => $_->{numberOfWinners}->{content},
1199             startTime => $_->{startTime}->{content},
1200             timezone => $_->{timezone}->{content},
1201             eventTypeId => $_->{eventTypeId}->{content},
1202             };
1203             }
1204             return $events;
1205             }
1206             return 0;
1207             }
1208              
1209             =head2 getInPlayMarkets
1210              
1211             Returns an arrayref of hashrefs of market data or 0 on failure. See L for details. Requires the following parameter:
1212              
1213             =over
1214              
1215             =item *
1216              
1217             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1218              
1219             =back
1220              
1221             Example
1222              
1223             my $inPlayMarkets = $betfair->getInPlayMarkets({exchangeId => 1});
1224              
1225             =cut
1226              
1227             sub getInPlayMarkets {
1228             my ($self, $args) = @_;
1229             my $checkParams = { exchangeId => ['exchangeId', 1] };
1230             return 0 unless $self->_checkParams($checkParams, $args);
1231             if ($self->_doRequest('getInPlayMarkets', $args) ) {
1232             my $response = $self->{response}->{'soap:Body'}->{'n:getInPlayMarketsResponse'}->{'n:Result'}->{'marketData'}->{content};
1233             my @markets;
1234             foreach (split /:/, $response) {
1235             next unless $_;
1236             my @data = split /~/, $_;
1237             push(@markets, {
1238             marketId => $data[0],
1239             marketName => $data[1],
1240             marketType => $data[2],
1241             marketStatus => $data[3],
1242             eventDate => $data[4],
1243             menuPath => $data[5],
1244             eventHierarchy => $data[6],
1245             betDelay => $data[7],
1246             exchangeId => $data[8],
1247             isoCountryCode => $data[9],
1248             lastRefresh => $data[10],
1249             numberOfRunner => $data[11],
1250             numberOfWinners => $data[12],
1251             totalAmountMatched => $data[13],
1252             bspMarket => $data[14],
1253             turningInPlay => $data[15],
1254             });
1255              
1256             }
1257             return \@markets;
1258             }
1259             return 0;
1260             }
1261              
1262             =head2 getMarket
1263              
1264             Returns a hash of market data or 0 on failure. See L for details. Requires:
1265              
1266             =over
1267              
1268             =item *
1269              
1270             marketId : integer which is the betfair id of the market
1271              
1272             =item *
1273              
1274             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1275              
1276             =back
1277              
1278             Example
1279              
1280             my $marketData = $betfair->getMarket({ marketId => 108690258,
1281             exchangeId => 2,
1282             });
1283              
1284             =cut
1285              
1286             sub getMarket {
1287             my ($self, $args) = @_;
1288             my $checkParams = { marketId => ['int', 1],
1289             exchangeId => ['exchangeId', 1],
1290             };
1291             return 0 unless $self->_checkParams($checkParams, $args);
1292             if ($self->_doRequest('getMarket', $args) ) {
1293             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketResponse'}->{'n:Result'}->{'market'};
1294             my $runners_list = $self->_forceArray($response->{'runners'}->{'n2:Runner'});
1295             my @parsed_runners = ();
1296             foreach (@{$runners_list}) {
1297             push(@parsed_runners, {
1298             name => $_->{'name'}->{content},
1299             selectionId => $_->{'selectionId'}->{content},
1300             });
1301             }
1302             return {
1303             name => $response->{'name'}->{content},
1304             marketId => $response->{'marketId'}->{content},
1305             eventTypeId => $response->{'eventTypeId'}->{content},
1306             marketTime => $response->{'marketTime'}->{content},
1307             marketStatus => $response->{'marketStatus'}->{content},
1308             runners => \@parsed_runners,
1309             marketDescription => $response->{'marketDescription'}->{content},
1310             activeFlag => 1,
1311             };
1312             }
1313             return 0;
1314             }
1315              
1316             =head2 getMarketInfo
1317              
1318             Returns a hash of market data or 0 on failure. See L for details. Requires a hashref with the following parameters:
1319              
1320             =over
1321              
1322             =item *
1323              
1324             marketId : integer which is the betfair id of the market
1325              
1326             =item *
1327              
1328             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1329              
1330             =back
1331              
1332             Example
1333              
1334             my $marketData = $betfair->getMarketInfo({ marketId => 108690258,
1335             exchangeId => 1,
1336             });
1337              
1338             =cut
1339              
1340             sub getMarketInfo {
1341             my ($self, $args) = @_;
1342             my $checkParams = { marketId => ['int', 1],
1343             exchangeId => ['exchangeId', 1],
1344             };
1345             return 0 unless $self->_checkParams($checkParams, $args);
1346             if ($self->_doRequest('getMarketInfo', $args) ) {
1347             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketInfoResponse'}->{'n:Result'}->{'marketLite'};
1348             return {
1349             delay => $response->{'delay'}->{content},
1350             numberOfRunners => $response->{'numberOfRunners'}->{content},
1351             marketSuspendTime => $response->{'marketSuspendTime'}->{content},
1352             marketTime => $response->{'marketTime'}->{content},
1353             marketStatus => $response->{'marketStatus'}->{content},
1354             openForBspBetting => $response->{'openForBspBetting'}->{content},
1355             };
1356             }
1357             return 0;
1358             }
1359              
1360             =head2 getMarketPrices
1361              
1362             Returns a hashref of market data or 0 on failure. See L for details. Requires:
1363              
1364             =over
1365              
1366             =item *
1367              
1368             marketId : integer which is the betfair id of the market
1369              
1370             =item *
1371              
1372             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1373              
1374             =item *
1375              
1376             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1377              
1378             =back
1379              
1380             Example
1381              
1382             my $marketPrices = $betfair->getMarketPrices({ marketId => 108690258
1383             exchangeId => 2,
1384             });
1385              
1386             =cut
1387              
1388             sub getMarketPrices {
1389             my ($self, $args) = @_;
1390             my $checkParams = {
1391             marketId => ['int', 1],
1392             currencyCode => ['currencyCode', 0],
1393             exchangeId => ['exchangeId', 1],
1394             };
1395             return 0 unless $self->_checkParams($checkParams, $args);
1396             if ($self->_doRequest('getMarketPrices', $args) ) {
1397             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketPricesResponse'}->{'n:Result'}->{'marketPrices'};
1398             my $runners_list = $self->_forceArray($response->{'runnerPrices'}->{'n2:RunnerPrices'});
1399             my @parsed_runners = ();
1400             foreach my $runner (@{$runners_list}) {
1401             my $bestPricesToBack = $self->_forceArray($runner->{bestPricesToBack}->{'n2:Price'});
1402             my @backPrices = ();
1403             foreach my $backPrice (@{$bestPricesToBack}){
1404             push(@backPrices, {
1405             amountAvailable => $backPrice->{amountAvailable}->{content},
1406             betType => $backPrice->{betType}->{content},
1407             depth => $backPrice->{depth}->{content},
1408             price => $backPrice->{price}->{content},
1409             });
1410             }
1411             my $bestPricesToLay = $self->_forceArray($runner->{bestPricesToLay}->{'n2:Price'});
1412             my @layPrices = ();
1413             foreach my $layPrice (@{$bestPricesToLay}){
1414             push(@layPrices, {
1415             amountAvailable => $layPrice->{amountAvailable}->{content},
1416             betType => $layPrice->{betType}->{content},
1417             depth => $layPrice->{depth}->{content},
1418             price => $layPrice->{price}->{content},
1419             });
1420             }
1421             push(@parsed_runners, {
1422             actualBSP => $runner->{'actualBSP'}->{content},
1423             asianLineId => $runner->{asianLineId}->{content},
1424             bestPricesToBack => \@backPrices,
1425             bestPricesToLay => \@layPrices,
1426             farBSP => $runner->{farBSP}->{content},
1427             handicap => $runner->{handicap}->{content},
1428             lastPriceMatched => $runner->{lastPriceMatched}->{content},
1429             nearBSP => $runner->{nearBSP}->{content},
1430             reductionFactor => $runner->{reductionFactor}->{content},
1431             selectionId => $runner->{selectionId}->{content},
1432             sortOrder => $runner->{sortOrder}->{content},
1433             totalAmountMatched => $runner->{totalAmountMatched}->{content},
1434             vacant => $runner->{vacant}->{content},
1435             });
1436             }
1437             return {
1438             bspMarket => $response->{bspMarket}->{content},
1439             currencyCode => $response->{currencyCode}->{content},
1440             delay => $response->{delay}->{content},
1441             discountAllowed => $response->{discountAllowed}->{content},
1442             lastRefresh => $response->{lastRefresh}->{content},
1443             marketBaseRate => $response->{marketBaseRate}->{content},
1444             marketId => $response->{marketId}->{content},
1445             marketInfo => $response->{marketInfo}->{content},
1446             marketStatus => $response->{marketStatus}->{content},
1447             numberOfWinners => $response->{numberOfWinners}->{content},
1448             removedRunners => $response->{removedRunners}->{content},
1449             runners => \@parsed_runners,
1450             };
1451             }
1452             return 0;
1453             }
1454              
1455             =head2 getMarketPricesCompressed
1456              
1457             Returns a hashref of market data including an arrayhashref of individual selection prices data. See L for details. Note that this method de-serializes the compressed string returned by the betfair method into a Perl data structure. Requires:
1458              
1459             =over
1460              
1461             =item *
1462              
1463             marketId : integer representing the betfair market id.
1464              
1465             =item *
1466              
1467             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1468              
1469             =item *
1470              
1471             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1472              
1473             =back
1474              
1475             Example
1476              
1477             my $marketPriceData = $betfair->getMarketPricesCompressed({marketId => 123456789});
1478              
1479             =cut
1480              
1481             sub getMarketPricesCompressed {
1482             my ($self, $args) = @_;
1483             my $checkParams = { marketId => ['int', 1],
1484             currencyCode=> ['currencyCode', 0],
1485             exchangeId => ['exchangeId', 1],
1486             };
1487             return 0 unless $self->_checkParams($checkParams, $args);
1488             if ($self->_doRequest('getMarketPricesCompressed', $args)) {
1489             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketPricesCompressedResponse'}->{'n:Result'}->{'marketPrices'}->{content};
1490             my @fields = split /:/, $response;
1491             my @marketData = split /~/, shift @fields;
1492             my @removedRunners;
1493             if ($marketData[9]){
1494             foreach (split /;/, $marketData[9]){
1495             next unless $_;
1496             my @removedRunnerData = split /,/;
1497             push (@removedRunners, {
1498             selectionId => $removedRunnerData[0],
1499             timeRemoved => $removedRunnerData[1],
1500             reductionFactor => $removedRunnerData[2],
1501             });
1502             }
1503             }
1504             my @selections;
1505             foreach my $selection (@fields) {
1506             my @selectionFields = split /\|/, $selection;
1507             next unless $selectionFields[0];
1508             my @selectionData = split /~/, $selectionFields[0];
1509             my (@backPrices, @layPrices);
1510             my @backPriceData = split /~/, $selectionFields[1];
1511             while (@backPriceData) {
1512             push (@backPrices, {
1513             price => shift @backPriceData,
1514             amount => shift @backPriceData,
1515             offerType => shift @backPriceData,
1516             depth => shift @backPriceData,
1517             });
1518             }
1519             my @layPriceData = split /~/, $selectionFields[2];
1520             while (@layPriceData) {
1521             push (@layPrices, {
1522             price => shift @layPriceData,
1523             amount => shift @layPriceData,
1524             offerType => shift @layPriceData,
1525             depth => shift @layPriceData,
1526             });
1527             }
1528             push (@selections, {
1529             backPrices => \@backPrices,
1530             layPrices => \@layPrices,
1531             selectionId => $selectionData[0],
1532             orderIndex => $selectionData[1],
1533             totalMatched => $selectionData[2],
1534             lastPriceMatched => $selectionData[3],
1535             asianHandicap => $selectionData[4],
1536             reductionFactor => $selectionData[5],
1537             vacant => $selectionData[6],
1538             farPriceSp => $selectionData[7],
1539             nearPriceSp => $selectionData[8],
1540             actualPriceSp => $selectionData[9],
1541             });
1542             }
1543             return { marketId => $args->{marketId},
1544             currency => $marketData[1],
1545             marketStatus => $marketData[2],
1546             InPlayDelay => $marketData[3],
1547             numberOfWinners => $marketData[4],
1548             marketInformation => $marketData[5],
1549             discountAllowed => $marketData[6],
1550             marketBaseRate => $marketData[7],
1551             refreshTimeMilliseconds => $marketData[8],
1552             BSPmarket => $marketData[10],
1553             removedRunnerInformation=> \@removedRunners,
1554             selections => \@selections,
1555             };
1556             }
1557             return 0;
1558             }
1559              
1560             =head2 getMUBets
1561              
1562             Returns an arrayref of hashes of bets or 0 on failure. See L for details. Requires:
1563              
1564             =over
1565              
1566             =item *
1567              
1568             betStatus : string of betfair betStatusEnum type, must be either matched, unmatched or both (M, U, MU). See L
1569              
1570             =item *
1571              
1572             orderBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
1573              
1574             =item *
1575              
1576             recordCount : integer of the maximum number of records to return
1577              
1578             =item *
1579              
1580             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1581              
1582             =item *
1583              
1584             noTotalRecordCount : string of either true or false
1585              
1586             =item *
1587              
1588             marketId : integer of the betfair market id for which current bets are required (optional)
1589              
1590             =item *
1591              
1592             betIds : an array of betIds (optional). If included, betStatus must be 'MU'.
1593              
1594             =item *
1595              
1596             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1597              
1598             =back
1599              
1600             Example
1601              
1602             my $muBets = $betfair->getMUBets({
1603             betStatus => 'MU',
1604             orderBy => 'PLACED_DATE',
1605             recordCount => 1000,
1606             startRecord => 0,
1607             noTotalRecordCount => 'true',
1608             sortOrder => 'ASC',
1609             marketId => 123456789,
1610             exchangeId => 1,
1611             });
1612              
1613             =cut
1614              
1615             sub getMUBets {
1616             my ($self, $args ) = @_;
1617             my $checkParams = {
1618             betStatus => ['betStatusEnum', 1],
1619             orderBy => ['betsOrderByEnum', 1],
1620             recordCount => ['int', 1,],
1621             startRecord => ['int', 1],
1622             marketId => ['int', 0],
1623             sortOrder => ['sortOrderEnum', 1],
1624             betIds => ['arrayInt', 0],
1625             exchangeId => ['exchangeId', 1],
1626             };
1627             return 0 unless $self->_checkParams($checkParams, $args);
1628             if (exists $args->{betIds}) {
1629             my @betIds = $args->{betIds};
1630             $args->{betIds} = {betId => \@betIds};
1631             }
1632             my $mu_bets = [];
1633             if ($self->_doRequest('getMUBets', $args)) {
1634             my $response = $self->_forceArray(
1635             $self->{response}->{'soap:Body'}->{'n:getMUBetsResponse'}->{'n:Result'}->{'bets'}->{'n2:MUBet'});
1636             foreach (@{$response} ) {
1637             push @{$mu_bets}, {
1638             marketId => $_->{'marketId'}->{content},
1639             betType => $_->{'betType'}->{content},
1640             transactionId => $_->{'transactionId'}->{content},
1641             size => $_->{'size'}->{content},
1642             placedDate => $_->{'placedDate'}->{content},
1643             betId => $_->{'betId'}->{content},
1644             betStatus => $_->{'betStatus'}->{content},
1645             betCategory_type => $_->{'betCategoryType'}->{content},
1646             betPersistence => $_->{'betPersistenceType'}->{content},
1647             matchedDate => $_->{'matchedDate'}->{content},
1648             selectionId => $_->{'selectionId'}->{content},
1649             price => $_->{'price'}->{content},
1650             bspLiability => $_->{'bspLiability'}->{content},
1651             handicap => $_->{'handicap'}->{content},
1652             asianLineId => $_->{'asianLineId'}->{content}
1653             };
1654             }
1655             return $mu_bets;
1656             }
1657             return 0;
1658             }
1659              
1660             =head2 getMUBetsLite
1661              
1662             Returns an arrayref of hashes of bets or 0 on failure. See L for details. Requires:
1663              
1664             =over
1665              
1666             =item *
1667              
1668             betStatus : string of betfair betStatusEnum type, must be either matched, unmatched or both (M, U, MU). See L
1669              
1670             =item *
1671              
1672             marketId : integer of the betfair market id for which current bets are required (optional)
1673              
1674             =item *
1675              
1676             excludeLastSecond : boolean string value ('true' or 'false'). If true then excludes bets matched in the past second (optional)
1677              
1678             =item *
1679              
1680             matchedSince : a string datetime for which to only return bets matched since this datetime. Must be a valid XML datetime format, see example below (optional)
1681              
1682             =item *
1683              
1684             orderBy : string of a valid BetsOrderByEnum types as defined by betfair. see L
1685              
1686             =item *
1687              
1688             recordCount : integer of the maximum number of records to return
1689              
1690             =item *
1691              
1692             startRecord : integer of the index of the first record to retrieve. The index is zero-based so 0 would indicate the first record in the resultset
1693              
1694             =item *
1695              
1696             sortOrder : string of the betfair sortOrder enumerated type (either 'ASC' or 'DESC'). See L for details.
1697              
1698             =item *
1699              
1700             betIds : an array of betIds (optional). If included, betStatus must be 'MU'.
1701              
1702             =item *
1703              
1704             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1705              
1706             =back
1707              
1708             Example
1709              
1710             my $muBets = $betfair->getMUBetsLite({
1711             betStatus => 'MU',
1712             orderBy => 'PLACED_DATE',
1713             excludeLastSecond => 'false',
1714             recordCount => 100,
1715             startRecord => 0,
1716             matchedSince => '2013-06-01T00:00:00.000Z',
1717             sortOrder => 'ASC',
1718             marketId => 123456789,
1719             exchangeId => 1,
1720             });
1721              
1722             =cut
1723              
1724             sub getMUBetsLite {
1725             my ($self, $args ) = @_;
1726             my $checkParams = {
1727             betStatus => ['betStatusEnum', 1],
1728             orderBy => ['betsOrderByEnum', 1],
1729             matchedSince => ['date', 0],
1730             excludeLastSecond => ['boolean', 0],
1731             recordCount => ['int', 1,],
1732             startRecord => ['int', 1],
1733             marketId => ['int', 0],
1734             sortOrder => ['sortOrderEnum', 1],
1735             betIds => ['arrayInt', 0],
1736             exchangeId => ['exchangeId', 1],
1737             };
1738             return 0 unless $self->_checkParams($checkParams, $args);
1739             if (exists $args->{betIds}) {
1740             my @betIds = $args->{betIds};
1741             $args->{betIds} = {betId => \@betIds};
1742             }
1743             my @muBetsLite;
1744             if ($self->_doRequest('getMUBetsLite', $args)) {
1745             my $response = $self->_forceArray(
1746             $self->{response}->{'soap:Body'}->{'n:getMUBetsLiteResponse'}->{'n:Result'}->{'betLites'}->{'n2:MUBetLite'});
1747             foreach (@{$response} ) {
1748             push (@muBetsLite, {
1749             betCategoryType => $_->{'betCategoryType'}->{content},
1750             betId => $_->{'betId'}->{content},
1751             betPersistenceType => $_->{'betPersistenceType'}->{content},
1752             betStatus => $_->{'betStatus'}->{content},
1753             bspLiability => $_->{'bspLiability'}->{content},
1754             marketId => $_->{'marketId'}->{content},
1755             betType => $_->{'betType'}->{content},
1756             size => $_->{'size'}->{content},
1757             transactionId => $_->{'transactionId'}->{content},
1758             });
1759             }
1760             return \@muBetsLite;
1761             }
1762             return 0;
1763             }
1764              
1765             =head2 getMarketProfitAndLoss
1766              
1767             Returns a hashref containing the profit and loss for a particular market. See L for details. Requires:
1768              
1769             =over
1770              
1771             =item *
1772              
1773             marketId : integer representing the betfair market id to return the market traded volume for
1774              
1775             =item *
1776              
1777             includeSettledBets : string boolean ('true' or 'false') to include settled bets in the P&L calculation (optional)
1778              
1779             =item *
1780              
1781             includeBspBets : string boolean ('true' or 'false') to include BSP bets in the P&L calculation
1782              
1783             =item *
1784              
1785             netOfCommission : string boolean ('true' or 'false') to include commission in P&L calculation (optional)
1786              
1787             =item *
1788              
1789             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1790              
1791             =back
1792              
1793             Example
1794              
1795             my $marketProfitAndLoss = $betfair->getMarketProfitAndLoss({marketId => 923456791,
1796             includeBspBets => 'false',
1797             exchangeId => 1,
1798             });
1799              
1800             =cut
1801              
1802             sub getMarketProfitAndLoss {
1803             my ($self, $args) = @_;
1804             my $checkParams = { marketId => ['int', 1],
1805             includeSettledBets => ['boolean', 0],
1806             includeBspBets => ['boolean', 1],
1807             netOfCommission => ['boolean', 0],
1808             exchangeId => ['exchangeId', 1],
1809             };
1810             return 0 unless $self->_checkParams($checkParams, $args);
1811             # handle mis-capitalization of marketID expected by betfair
1812             $args->{marketID} = $args->{marketId};
1813             delete $args->{marketId};
1814             if ($self->_doRequest('getMarketProfitAndLoss', $args)) {
1815             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketProfitAndLossResponse'}->{'n:Result'};
1816             my $profitAndLoss = {
1817             annotations => [],
1818             commissionApplied => $response->{commissionApplied}->{content},
1819             currencyCode => $response->{currencyCode}->{content},
1820             includesSettledBets => $response->{includesSettledBets}->{content},
1821             includesBspBets => $response->{includesBspBets}->{content},
1822             marketId => $response->{marketId}->{content},
1823             marketName => $response->{marketName}->{content},
1824             marketStatus => $response->{marketStatus}->{content},
1825             unit => $response->{unit}->{content},
1826             };
1827             if (exists $response->{annotations}->{'n2:ProfitAndLoss'}) {
1828             my $oddsAnnotations = $self->_forceArray($response->{annotations}->{'n2:ProfitAndLoss'});
1829             foreach (@$oddsAnnotations) {
1830             push @{$profitAndLoss->{annotations}}, {
1831             ifWin => $_->{ifWin}->{content},
1832             selectionId => $_->{selectionId}->{content},
1833             selectionName => $_->{selectionName}->{content},
1834             ifLoss => $_->{ifLoss}->{content},
1835             to => $_->{to}->{content},
1836             from => $_->{from}->{content},
1837             };
1838             }
1839             }
1840             return $profitAndLoss;
1841             }
1842             return 0;
1843             }
1844              
1845              
1846             =head2 getMarketTradedVolume
1847              
1848             Returns an arrayref of hashrefs containing the traded volume for a particular market and selection. See L for details. Requires:
1849              
1850             =over
1851              
1852             =item *
1853              
1854             marketId : integer representing the betfair market id to return the market traded volume for.
1855              
1856             =item *
1857              
1858             selectionId : integer representing the betfair selection id of the selection to return matched volume for.
1859              
1860             =item *
1861              
1862             asianLineId : integer representing the betfair asian line id - this is optional unless the request is for an asian line market.
1863              
1864             =item *
1865              
1866             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1867              
1868             =item *
1869              
1870             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1871              
1872             =back
1873              
1874             Example
1875              
1876             my $marketVolume = $betfair->getMarketTradedVolume({marketId => 923456791,
1877             selectionId => 30571,
1878             exchangeId => 2,
1879             });
1880              
1881             =cut
1882              
1883             sub getMarketTradedVolume {
1884             my ($self, $args) = @_;
1885             my $checkParams = { marketId => ['int', 1],
1886             asianLineId => ['int', 0],
1887             selectionId => ['int', 1],
1888             currencyCode=> ['currencyCode', 0],
1889             exchangeId => ['exchangeId', 1],
1890             };
1891             return 0 unless $self->_checkParams($checkParams, $args);
1892             if ($self->_doRequest('getMarketTradedVolume', $args)) {
1893             my $response = $self->_forceArray(
1894             $self->{response}->{'soap:Body'}->{'n:getMarketTradedVolumeResponse'}->{'n:Result'}->{'priceItems'}->{'n2:VolumeInfo'});
1895             my $tradedVolume = [];
1896             foreach (@{$response}) {
1897             push @{$tradedVolume}, {
1898             odds => $_->{odds}->{content},
1899             totalMatchedAmount => $_->{totalMatchedAmount}->{content},
1900             totalBspBackMatchedAmount => $_->{totalBspBackMatchedAmount}->{content},
1901             totalBspLiabilityMatchedAmount => $_->{totalBspLiabilityMatchedAmount}->{content},
1902             };
1903             }
1904             return $tradedVolume;
1905             }
1906             return 0;
1907             }
1908              
1909              
1910             =head2 getMarketTradedVolumeCompressed
1911              
1912             Returns an arrayref of selections with their total matched amounts plus an array of all traded volume with the trade size and amount. See L for details. Note that this service de-serializes the compressed string return by betfair into a Perl data structure. Requires:
1913              
1914             =over
1915              
1916             =item *
1917              
1918             marketId : integer representing the betfair market id to return the market traded volume for.
1919              
1920             =item *
1921              
1922             currencyCode : string representing the three letter ISO currency code. Only certain currencies are accepted by betfair GBP, USD, EUR, NOK, SGD, SEK, AUD, CAD, HKD, DKK (optional)
1923              
1924             =item *
1925              
1926             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1927              
1928             =back
1929              
1930             Example
1931              
1932             my $marketVolume = $betfair->getMarketTradedVolumeCompressed({ marketId => 923456791,
1933             exchangeId => 2,
1934             });
1935              
1936             =cut
1937              
1938             sub getMarketTradedVolumeCompressed {
1939             my ($self, $args) = @_;
1940             my $checkParams = {
1941             marketId => ['int', 1],
1942             currencyCode => ['currencyCode', 0],
1943             exchangeId => ['exchangeId', 1],
1944             };
1945             return 0 unless $self->_checkParams($checkParams, $args);
1946             if ($self->_doRequest('getMarketTradedVolumeCompressed', $args)) {
1947             my $response = $self->{response}->{'soap:Body'}->{'n:getMarketTradedVolumeCompressedResponse'}->{'n:Result'}->{'tradedVolume'}->{content};
1948             my $marketTradedVolume = { marketId => $args->{marketId} };
1949             foreach my $selection (split /:/, $response) {
1950             my @selectionFields = split /\|/, $selection;
1951             next unless defined $selectionFields[0];
1952             my @selectionData = split /~/, shift @selectionFields;
1953             my $tradedAmounts = [];
1954             foreach (@selectionFields) {
1955             my ($odds, $size) = split /~/, $_;
1956             push @{$tradedAmounts}, {
1957             odds => $odds,
1958             size => $size,
1959             };
1960             }
1961              
1962             push @{$marketTradedVolume->{selections}}, {
1963             selectionId => $selectionData[0],
1964             asianLineId => $selectionData[1],
1965             actualBSP => $selectionData[2],
1966             totalBSPBackMatched => $selectionData[3],
1967             totalBSPLiabilityMatched => $selectionData[4],
1968             tradedAmounts => $tradedAmounts,
1969             } if (defined $selectionData[0]);
1970             }
1971             return $marketTradedVolume;
1972             }
1973             return 0;
1974             }
1975              
1976             =head2 getPrivateMarkets
1977              
1978             Returns an arrayref of private markets - see L for details. Requires a hashref with the following arguments:
1979              
1980             =over
1981              
1982             =item *
1983              
1984             eventTypeId : integer representing the betfair id of the event type to return private markets for.
1985              
1986             =item *
1987              
1988             marketType : string of the betfair marketType enum see L.
1989              
1990             =item *
1991              
1992             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
1993              
1994             =back
1995              
1996             Example
1997              
1998             my $privateMarkets = $betfair->getPrivateMarkets({ eventTypeId => 1,
1999             marketType => 'O',
2000             exchangeId => 1,
2001             });
2002              
2003             =cut
2004              
2005             sub getPrivateMarkets {
2006             my ($self, $args) = @_;
2007             my $checkParams = { eventTypeId => ['int', 1],
2008             marketType => ['marketTypeEnum', 1],
2009             exchangeId => ['exchangeId', 1],
2010             };
2011             return 0 unless $self->_checkParams($checkParams, $args);
2012             if ($self->_doRequest('getPrivateMarkets', $args)) {
2013             my $response = $self->_forceArray(
2014             $self->{response}->{'soap:Body'}->{'n:getPrivateMarketsResponse'}->{'n:Result'}->{'privateMarkets'}->{'n2:PrivateMarket'});
2015             my @privateMarkets;
2016             foreach (@{$response}) {
2017             push(@privateMarkets, {
2018             name => $_->{name}->{content},
2019             marketId => $_->{marketId}->{content},
2020             menuPath => $_->{menuPath}->{content},
2021             eventHierarchy => $_->{eventHierarchy}->{content},
2022             });
2023             }
2024             return \@privateMarkets;
2025             }
2026             return 0;
2027             }
2028              
2029             =head2 getSilks
2030              
2031             This method is not available on the free betfair API.
2032              
2033             Returns an arrayref of market racing silks data or 0 on failure. See L for details. Requires the following parameters:
2034              
2035             =over
2036              
2037             =item *
2038              
2039             markets : an arrayref of integers representing betfair market ids
2040              
2041             =item *
2042              
2043             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2044              
2045             =back
2046              
2047             Example
2048              
2049             my $silks = $betfair->getSilksV2({ markets => [123456,9273649],
2050             exchangeId => 1,
2051             });
2052              
2053             =cut
2054              
2055             sub getSilks {
2056             my ($self, $args) = @_;
2057             my $checkParams = {
2058             markets => ['arrayInt', 1],
2059             exchangeId => ['exchangeId', 1],
2060             };
2061             return 0 unless $self->_checkParams($checkParams, $args);
2062             # adjust args into betfair api required structure
2063             my $params = { markets => { int => $args->{markets} },
2064             exchangeId => $args->{exchangeId},
2065             };
2066             if ($self->_doRequest('getSilks', $params)) {
2067             my $silks = [];
2068             my $response = $self->_forceArray(
2069             $self->{response}->{'soap:Body'}->{'n:getSilksResponse'}->{'n:Result'}->{'marketDisplayDetails'}->{'n2:MarketDisplayDetail'});
2070             foreach (@$response) {
2071             my $market = $_->{marketId}->{content};
2072             next unless $market;
2073             my $runners = $self->_forceArray($_->{racingSilks}->{'n2:RacingSilk'});
2074             my @racingSilks;
2075             foreach (@$runners) {
2076             push(@racingSilks, {
2077             selectionId => $_->{selectionId}->{content},
2078             silksURL => 'http://content-cache.betfair.com/feeds_images/Horses/SilkColours/' . $_->{silksURL}->{content},
2079             silksText => $_->{silksText}->{content},
2080             trainerName => $_->{trainerName}->{content},
2081             ageWeight => $_->{ageWeight}->{content},
2082             form => $_->{form}->{content},
2083             daysSinceLastRun => $_->{daysSince}->{content},
2084             jockeyClaim => $_->{jockeyClaim}->{content},
2085             wearing => $_->{wearing}->{content},
2086             saddleClothNumber=> $_->{saddleCloth}->{content},
2087             stallDraw => $_->{stallDraw}->{content},
2088             });
2089             }
2090             push(@$silks, {
2091             marketId => $market,
2092             runners => \@racingSilks,
2093             });
2094             }
2095             return $silks;
2096             }
2097             return 0;
2098             }
2099              
2100             =head2 getSilksV2
2101              
2102             This method is not available on the free betfair API.
2103              
2104             Returns an arrayref of market racing silks data or 0 on failure. See L for details. Requires the following parameters:
2105              
2106             =over
2107              
2108             =item *
2109              
2110             markets : an arrayref of integers representing betfair market ids
2111              
2112             =item *
2113              
2114             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2115              
2116             =back
2117              
2118             Example
2119              
2120             my $silks = $betfair->getSilksV2({ markets => [123456,9273649],
2121             exchangeId => 1,
2122             });
2123              
2124             =cut
2125              
2126             sub getSilksV2 {
2127             my ($self, $args) = @_;
2128             my $checkParams = {
2129             markets => ['arrayInt', 1],
2130             exchangeId => ['exchangeId', 1],
2131             };
2132             return 0 unless $self->_checkParams($checkParams, $args);
2133             # adjust args into betfair api required structure
2134             my $params = { markets => { int => $args->{markets} },
2135             exchangeId => $args->{exchangeId},
2136             };
2137             if ($self->_doRequest('getSilksV2', $params)) {
2138             my $silks = [];
2139             my $response = $self->_forceArray(
2140             $self->{response}->{'soap:Body'}->{'n:getSilksV2Response'}->{'n:Result'}->{'marketDisplayDetails'}->{'n2:MarketDisplayDetail'});
2141             foreach (@$response) {
2142             my $market = $_->{marketId}->{content};
2143             next unless $market;
2144             my $runners = $self->_forceArray($_->{racingSilks}->{'n2:RacingSilk'});
2145             my @racingSilks;
2146             foreach (@$runners) {
2147             push(@racingSilks, {
2148             selectionId => $_->{selectionId}->{content},
2149             silksURL => 'http://content-cache.betfair.com/feeds_images/Horses/SilkColours/' . $_->{silksURL}->{content},
2150             silksText => $_->{silksText}->{content},
2151             trainerName => $_->{trainerName}->{content},
2152             ageWeight => $_->{ageWeight}->{content},
2153             form => $_->{form}->{content},
2154             daysSinceLastRun => $_->{daysSince}->{content},
2155             jockeyClaim => $_->{jockeyClaim}->{content},
2156             wearing => $_->{wearing}->{content},
2157             saddleClothNumber => $_->{saddleCloth}->{content},
2158             stallDraw => $_->{stallDraw}->{content},
2159             ownerName => $_->{ownerName}->{content},
2160             jockeyName => $_->{jockeyName}->{content},
2161             colour => $_->{colour}->{content},
2162             sex => $_->{sex}->{content},
2163             forecastPriceNumerator => $_->{forecastPriceNumerator}->{content},
2164             forecastPriceDenominator=> $_->{forecastPriceDenominator}->{content},
2165             officialRating => $_->{officialRating}->{content},
2166             sire => {name => $_->{sire}->{name}->{content},
2167             bred => $_->{sire}->{bred}->{content},
2168             yearBorn=> $_->{sire}->{yearBorn}->{content},
2169             },
2170             dam => {name => $_->{dam}->{name}->{content},
2171             bred => $_->{dam}->{bred}->{content},
2172             yearBorn=> $_->{dam}->{yearBorn}->{content},
2173             },
2174             damSire => {name => $_->{damSire}->{name}->{content},
2175             bred => $_->{damSire}->{bred}->{content},
2176             yearBorn=> $_->{damSire}->{yearBorn}->{content},
2177             },
2178             });
2179             }
2180             push(@$silks, {
2181             marketId => $market,
2182             runners => \@racingSilks,
2183             });
2184             }
2185             return $silks;
2186             }
2187             return 0;
2188             }
2189              
2190             =head1 BET PLACEMENT API METHODS
2191              
2192             =head2 cancelBets
2193              
2194             Cancels up to 40 unmatched and active bets on betfair. Returns an arrayref of hashes of cancelled bets. See L for details. Requires a hashref with the following parameters:
2195              
2196             =over
2197              
2198             =item *
2199              
2200             betIds : an arrayref of integers of betIds that should be cancelled, up to 40 betIds are permitted by betfair.
2201              
2202             =item *
2203              
2204             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2205              
2206             =back
2207              
2208             Example
2209              
2210             my $cancelledBetsResults = $betfair->cancelBets({betIds => [123456789, 987654321]
2211             exchangeId => 2,
2212             });
2213              
2214             =cut
2215              
2216             sub cancelBets {
2217             my ($self, $args) = @_;
2218             my $checkParams = {
2219             betIds => ['arrayInt', 1],
2220             exchangeId => ['exchangeId', 1],
2221             };
2222             return 0 unless $self->_checkParams($checkParams, $args);
2223             # adjust args into betfair api required structure
2224             my $params = { bets => { CancelBets => {betId => $args->{betIds}} },
2225             exchangeId => $args->{exchangeID},
2226             };
2227             my $cancelled_bets = [];
2228             if ($self->_doRequest('cancelBets', $params)) {
2229             my $response = $self->_forceArray(
2230             $self->{response}->{'soap:Body'}->{'n:cancelBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:CancelBetsResult'});
2231             foreach (@{$response} ) {
2232             $cancelled_bets = _add_cancelled_bet($cancelled_bets, $_);
2233             }
2234             return $cancelled_bets;
2235             }
2236             return 0;
2237             sub _add_cancelled_bet {
2238             my ($cancelled_bets, $bet_to_be_added) = @_;
2239             push(@$cancelled_bets, {
2240             success => $bet_to_be_added->{'success'}->{content},
2241             result_code => $bet_to_be_added->{'resultCode'}->{content},
2242             size_matched => $bet_to_be_added->{'sizeMatched'}->{content},
2243             size_cancelled => $bet_to_be_added->{'sizeCancelled'}->{content},
2244             bet_id => $bet_to_be_added->{'betId'}->{content},
2245             });
2246             return $cancelled_bets;
2247             }
2248             }
2249              
2250             =head2 cancelBetsByMarket
2251              
2252             Receives an arrayref of marketIds and cancels all unmatched bets on those markets. Returns an arrayref of hashrefs of market ids and results. See L for details. Requires a hashref with the following parameters:
2253              
2254             =over
2255              
2256             =item *
2257              
2258             markets : arrayref of integers representing market ids.
2259              
2260             =item *
2261              
2262             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2263              
2264             =back
2265              
2266             Example
2267              
2268             my $cancelledBets = $betfair->cancelBetsByMarket({markets => [123456789, 432596611],
2269             exchangeId => 1,
2270             });
2271              
2272             =cut
2273              
2274             sub cancelBetsByMarket {
2275             my ($self, $args) = @_;
2276             my $checkParams = {
2277             markets => ['arrayInt', 1],
2278             exchangeId => ['exchangeId', 1],
2279             };
2280             return 0 unless $self->_checkParams($checkParams, $args);
2281             # adjust args into betfair api required structure
2282             my $params = { markets => { int => $args->{markets} },
2283             exchangeId => $args->{exchangeId},
2284             };
2285             my $cancelled_bets = [];
2286             if ($self->_doRequest('cancelBetsByMarket', $params)) {
2287             my $response = $self->_forceArray(
2288             $self->{response}->{'soap:Body'}->{'n:cancelBetsByMarketResponse'}->{'n:Result'}->{results}->{'n2:CancelBetsByMarketResult'});
2289             foreach (@{$response} ) {
2290             push(@$cancelled_bets, {
2291             marketId => $_->{'marketId'}->{content},
2292             resultCode => $_->{'resultCode'}->{content},
2293             });
2294             }
2295             return $cancelled_bets;
2296             }
2297             return 0;
2298             }
2299              
2300              
2301             =head2 placeBets
2302              
2303             Places up to 60 bets on betfair and returns an array of results or zero on failure. See L for details. Requires:
2304              
2305             =over
2306              
2307             =item *
2308              
2309             bets : an arrayref of hashes of bets. Up to 60 hashes are permitted by betfair. Every bet hash should contain:
2310              
2311             =over 8
2312              
2313             =item *
2314              
2315             asianLineId : integer of the ID of the asian handicap market, usually 0 unless betting on an asian handicap market
2316              
2317             =item *
2318              
2319             betCategoryType : a string of the betCategoryTypeEnum, usually 'E' for exchange, see L for details.
2320              
2321             =item *
2322              
2323             betPersistenceType : a string of the betPersistenceTypeEnum, usually 'NONE' for standard exchange bets. See L for details.
2324              
2325             =item *
2326              
2327             betType : a string of the betTypeEnum. Either 'B' to back or 'L' to lay.
2328              
2329             =item *
2330              
2331             bspLiability : a number of the maximum amount to risk for a bsp bet. For a back / lay bet this is equivalent to the whole stake amount.
2332              
2333             =item *
2334              
2335             marketId : integer of the marketId for which the bet should be placed.
2336              
2337             =item *
2338              
2339             price : number of the decimal odds for the bet.
2340              
2341             =item *
2342              
2343             selectionId : integer of the betfair id of the runner (selection option) that the bet should be placed on.
2344              
2345             =item *
2346              
2347             size : number for the stake amount for this bet.
2348              
2349             =back
2350              
2351             =item *
2352              
2353             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2354              
2355             =back
2356              
2357             Example
2358              
2359             $myBetPlacedResults = $betfair->placeBets({
2360             bets => [{ asianLineId => 0,
2361             betCategoryType => 'E',
2362             betPersistenceType => 'NONE',
2363             betType => 'B',
2364             bspLiability => 2,
2365             marketId => 123456789,
2366             price => 5,
2367             selectionId => 99,
2368             size => 10,
2369             }],
2370             exchangeId => 1,
2371             });
2372              
2373             =cut
2374              
2375             sub placeBets {
2376             my ($self, $args) = @_;
2377             # handle exchange id separately
2378             if (exists $args->{exchangeId}) {
2379             return 0 unless $self->_checkParams({exchangeId => ['exchangeId', 1]}, {exchangeId => $args->{exchangeId}});
2380             }
2381             else {
2382             return 0;
2383             }
2384             my $checkParams = {
2385             asianLineId => ['int', 1],
2386             betCategoryType => ['betCategoryTypeEnum', 1],
2387             betPersistenceType => ['betPersistenceTypeEnum', 1],
2388             betType => ['betTypeEnum', 1],
2389             bspLiability => ['int', 1],
2390             marketId => ['int', 1],
2391             price => ['decimal', 1],
2392             selectionId => ['int', 1],
2393             size => ['decimal', 1],
2394             };
2395             foreach (@{$args->{bets}}) {
2396             return 0 unless $self->_checkParams($checkParams, $_);
2397             }
2398             # adjust args into betfair api required structure
2399             my $params = { bets => { PlaceBets => $args->{bets} },
2400             exchangeId => $args->{exchangeId},
2401             };
2402             if ($self->_doRequest('placeBets', $params)) {
2403             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:placeBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:PlaceBetsResult'});
2404             my $placed_bets = [];
2405             foreach (@{$response}) {
2406             push @{$placed_bets}, {
2407             success => $_->{'success'}->{content},
2408             result_code => $_->{'resultCode'}->{content},
2409             bet_id => $_->{'betId'}->{content},
2410             size_matched => $_->{'sizeMatched'}->{content},
2411             avg_price_matched => $_->{'averagePriceMatched'}->{content}
2412             };
2413             }
2414             return $placed_bets;
2415             }
2416             return 0;
2417             }
2418              
2419             =head2 updateBets
2420              
2421             Updates existing unmatched bets on betfair: the size, price and persistence can be updated. Note that only the size or the price can be updated in one request, if both parameters are provided betfair ignores the new size value. Returns an arrayref of hashes of updated bet results. See L for details. Requires:
2422              
2423             =over
2424              
2425             =item *
2426              
2427             bets : an arrayref of hashes of bets to be updated. Each hash represents one bet and must contain the following key / value pairs:
2428              
2429             =over 8
2430              
2431             =item *
2432              
2433             betId : integer of the betId to be updated
2434              
2435             =item *
2436              
2437             newBetPersistenceType : string of the betfair betPersistenceTypeEnum to be updated to see L for more details.
2438              
2439             =item *
2440              
2441             newPrice : number for the new price of the bet
2442              
2443             =item *
2444              
2445             newSize : number for the new size of the bet
2446              
2447             =item *
2448              
2449             oldBetPersistenceType : string of the current bet's betfair betPersistenceTypeEnum see L for more details.
2450              
2451             =item *
2452              
2453             oldPrice : number for the old price of the bet
2454              
2455             =item *
2456              
2457             oldSize : number for the old size of the bet
2458              
2459             =back
2460              
2461             =item *
2462              
2463             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2464              
2465             =back
2466              
2467             Example
2468              
2469             my $updateBetDetails = $betfair->updateBets({
2470             bets => [{betId => 12345,
2471             newBetPersistenceType => 'NONE',
2472             newPrice => 5,
2473             newSize => 10,
2474             oldBetPersistenceType => 'NONE',
2475             oldPrice => 2,
2476             oldSize => 10,
2477             }],
2478             exchangeId => 1,
2479             });
2480              
2481              
2482             =cut
2483              
2484             sub updateBets {
2485             my ($self, $args) = @_;
2486             # handle exchange id separately
2487             if (exists $args->{exchangeId}) {
2488             return 0 unless $self->_checkParams({exchangeId => ['exchangeId', 1]}, {exchangeId => $args->{exchangeId}});
2489             }
2490             else {
2491             return 0;
2492             }
2493             my $checkParams = {
2494             betId => ['int', 1],
2495             newBetPersistenceType => ['betPersistenceTypeEnum', 1],
2496             oldBetPersistenceType => ['betPersistenceTypeEnum', 1],
2497             newSize => ['decimal', 1],
2498             oldSize => ['decimal', 1],
2499             newPrice => ['decimal', 1],
2500             oldPrice => ['decimal', 1],
2501             };
2502             foreach (@{$args->{bets}}) {
2503             return 0 unless $self->_checkParams($checkParams, $_);
2504             }
2505             my $params = {
2506             bets => { UpdateBets => $args->{bets} },
2507             exchangeId => $args->{exchangeId},
2508             };
2509             my $updated_bets = [];
2510             if ($self->_doRequest('updateBets', $params)) {
2511             my $response = $self->_forceArray($self->{response}->{'soap:Body'}->{'n:updateBetsResponse'}->{'n:Result'}->{'betResults'}->{'n2:UpdateBetsResult'});
2512             foreach (@{$response}) {
2513             push @{$updated_bets}, {
2514             success => $_->{'success'}->{content},
2515             size_cancelled => $_->{'sizeCancelled'}->{content},
2516             new_price => $_->{'newPrice'}->{content},
2517             bet_id => $_->{'betId'}->{content},
2518             new_bet_id => $_->{'newBetId'}->{content},
2519             result_code => $_->{content}->{content},
2520             new_size => $_->{'newSize'}->{content},
2521             };
2522             }
2523             return $updated_bets;
2524             }
2525             return 0;
2526             }
2527              
2528              
2529             =head1 ACCOUNT MANAGEMENT API METHODS
2530              
2531             =head2 addPaymentCard
2532              
2533             Adds a payment card to your betfair account. Returns an arrayref of hashes of payment card responses or 0 on failure. See L. Requires:
2534              
2535             =over
2536              
2537             =item *
2538              
2539             cardNumber : string of the card number
2540              
2541             =item *
2542              
2543             cardType : string of a valid betfair cardTypeEnum (e.g. 'VISA'). See L
2544              
2545             =item *
2546              
2547             cardStatus : string of a valid betfair paymentCardStatusEnum, either 'LOCKED' or 'UNLOCKED'
2548              
2549             =item *
2550              
2551             startDate : string of the card start date, optional depending on type of card
2552              
2553             =item *
2554              
2555             expiryDate : string of the card expiry date
2556              
2557             =item *
2558              
2559             issueNumber : string of the issue number or NULL if the cardType is not Solo or Switch
2560              
2561             =item *
2562              
2563             billingName : name of person on the billing account for the card
2564              
2565             =item *
2566              
2567             nickName : string of the card nickname must be less than 9 characters
2568              
2569             =item *
2570              
2571             password : string of the betfair account password
2572              
2573             =item *
2574              
2575             address1 : string of the first line of the address for the payment card
2576              
2577             =item *
2578              
2579             address2 : string of the second line of the address for the payment card
2580              
2581             =item *
2582              
2583             address3 : string of the third line of the address for the payment card (optional)
2584              
2585             =item *
2586              
2587             address4 : string of the fourth line of the address for the payment card (optional)
2588              
2589             =item *
2590              
2591             town : string of the town for the payment card
2592              
2593             =item *
2594              
2595             county : string of the county for the payment card
2596              
2597             =item *
2598              
2599             zipCode : string of the zip / postal code for the payment card
2600              
2601             =item *
2602              
2603             country : string of the country for the payment card
2604              
2605             =back
2606              
2607             Example
2608              
2609             my $addPaymentCardResponse = $betfair->addPaymentCard({
2610             cardNumber => '1234123412341234',
2611             cardType => 'VISA',
2612             cardStatus => 'UNLOCKED',
2613             startDate => '0113',
2614             expiryDate => '0116',
2615             issueNumber => 'NULL',
2616             billingName => 'The Sillymoose',
2617             nickName => 'democard',
2618             password => 'password123',
2619             address1 => 'Tasty bush',
2620             address2 => 'Mountain Plains',
2621             town => 'Hoofton',
2622             zipCode => 'MO13FR',
2623             county => 'Mooshire',
2624             country => 'UK',
2625             });
2626              
2627             =cut
2628              
2629             sub addPaymentCard {
2630             my ($self, $args) = @_;
2631             my $checkParams = {
2632             cardNumber => ['int', 1],
2633             cardType => ['cardTypeEnum', 1],
2634             cardStatus => ['cardStatusEnum', 1],
2635             startDate => ['cardDate', 1],
2636             expiryDate => ['cardDate', 1],
2637             issueNumber => ['int', 1],
2638             billingName => ['string', 1],
2639             nickName => ['string9', 1],
2640             password => ['password', 1],
2641             address1 => ['string', 1],
2642             address2 => ['string', 1],
2643             address3 => ['string', 0],
2644             address4 => ['string', 0],
2645             town => ['string', 1],
2646             zipCode => ['string', 1],
2647             county => ['string', 1],
2648             country => ['string', 1],
2649              
2650             };
2651             return 0 unless $self->_checkParams($checkParams, $args);
2652             $args->{exchangeId} = 3;
2653             if ($self->_doRequest('addPaymentCard', $args) ) {
2654             return $self->_addPaymentCardLine([], $self->{response}->{'soap:Body'}->{'n:addPaymentCardResponse'}->{'n:Result'}->{'n2:PaymentCard'});
2655             }
2656             return 0;
2657             }
2658              
2659             =head2 deletePaymentCard
2660              
2661             Deletes a registered payment card from your betfair account. See L for further details. Returns the betfair response as a hashref or 0 on failure. Requires:
2662              
2663             =over
2664              
2665             =item *
2666              
2667             nickName : string of the card nickname to be deleted (must be less than 9 characters)
2668              
2669             =item *
2670              
2671             password : string of the betfair account password
2672              
2673             =back
2674              
2675             Example
2676              
2677             my $deleteCardResponse = $betfair->deletePaymentCard({
2678             nickName => 'checking',
2679             password => 'password123',
2680             });
2681              
2682             =cut
2683              
2684             sub deletePaymentCard {
2685             my ($self, $args) = @_;
2686             my $checkParams = {
2687             nickName => ['string9', 1],
2688             password => ['password', 1],
2689             };
2690             return 0 unless $self->_checkParams($checkParams, $args);
2691             $args->{exchangeId} = 3;
2692             if ($self->_doRequest('deletePaymentCard', $args)) {
2693             my $response = $self->{response}->{'soap:Body'}->{'n:deletePaymentCardResponse'}->{'n:Result'};
2694             return {
2695             nickName => $response->{nickName}->{content},
2696             billingName => $response->{billingName}->{content},
2697             cardShortNumber => $response->{cardShortNumber}->{content},
2698             cardType => $response->{cardType}->{content},
2699             issuingCountry => $response->{issuingCountry}->{content},
2700             expiryDate => $response->{expiryDate}->{content},
2701             };
2702             }
2703             return 0;
2704             }
2705              
2706             =head2 depositFromPaymentCard
2707              
2708             Deposits money in your betfair account using a payment card. See L for further details. Returns the betfair response as a hashref or 0 on failure. Requires:
2709              
2710             =over
2711              
2712             =item *
2713              
2714             amount : number which represents the amount of money to deposit
2715              
2716             =item *
2717              
2718             cardIdentifier : string of the nickname for the payment card
2719              
2720             =item *
2721              
2722             cv2 : string of the CV2 digits from the payment card (also known as the security digits)
2723              
2724             =item *
2725              
2726             password : string of the betfair account password
2727              
2728             =back
2729              
2730             Example
2731              
2732             my $depositResponse = $betfair->depositFromPaymentCard({
2733             amount => 10,
2734             cardIdentifier => 'checking',
2735             cv2 => '999',
2736             password => 'password123',
2737             });
2738              
2739             =cut
2740              
2741             sub depositFromPaymentCard {
2742             my ($self, $args) = @_;
2743             my $checkParams = {
2744             amount => ['decimal', 1],
2745             cardIdentifier => ['string9', 1],
2746             cv2 => ['cv2', 1],
2747             password => ['password', 1],
2748             };
2749             return 0 unless $self->_checkParams($checkParams, $args);
2750             $args->{exchangeId} = 3;
2751             if ($self->_doRequest('depositFromPaymentCard', $args)) {
2752             my $deposit_response = $self->{response}->{'soap:Body'}->{'n:depositFromPaymentCardResponse'}->{'n:Result'};
2753             return {
2754             fee => $deposit_response->{'fee'}->{content},
2755             transactionId => $deposit_response->{'transactionId'}->{content},
2756             minAmount => $deposit_response->{'minAmount'}->{content},
2757             errorCode => $deposit_response->{'errorCode'}->{content},
2758             minorErrorCode => $deposit_response->{'minorErrorCode'}->{content},
2759             maxAmount => $deposit_response->{'maxAmount'}->{content},
2760             netAmount => $deposit_response->{'netAmount'}->{content},
2761             };
2762             }
2763             return 0;
2764             }
2765              
2766             =head2 forgotPassword
2767              
2768             NB. This service is largely redundant as it requires an authenticated session to work, however it is included for the sake of completeness.
2769              
2770             Resets the betfair account password via a 2 stage process. See L and the example below for details. Returns the betfair response as a hashref for stage 1, 1 on a successful passwprd reset or 0 on failure. Note that this service can be difficult to succeed with - user the getError method to inspect the response message from betfair. Requires:
2771              
2772             =over
2773              
2774             =item *
2775              
2776             username : string of the betfair username for the account to reset the password for
2777              
2778             =item *
2779              
2780             emailAddress : string of the betfair account email address
2781              
2782             =item *
2783              
2784             countryOfResidence : string of the country of residence the betfair account is registered to
2785              
2786             =item *
2787              
2788             forgottenPasswordAnswer1 : string of the answer to question1 as returned by this service on the first request (optional)
2789              
2790             =item *
2791              
2792             forgottenPasswordAnswer2 : string of the answer to question2 as returned by this service on the first request (optional)
2793              
2794             =item *
2795              
2796             newPassword : string of the new account password (optional)
2797              
2798             =item *
2799              
2800             newPasswordRepeat : string of the new account password (optional)
2801              
2802             =back
2803              
2804             Example
2805              
2806             use Data::Dumper;
2807              
2808             my $securityQuestions = $betfair->forgotPassword({
2809             username => 'sillymoose',
2810             emailAddress => 'sillymoos@cpan.org',
2811             countryOfResidence => 'United Kingdom',
2812             });
2813             print Dumper($securityQuestions);
2814              
2815             # now call service again with answers to security questions and new password parameters
2816             my $resetPasswordResponse = $betfair->forgotPassword({
2817             username => 'sillymoose',
2818             emailAddress => 'sillymoos@cpan.org',
2819             countryOfResidence => 'United Kingdom',
2820             forgottenPasswordAnswer1 => 'dasher',
2821             forgottenPasswordAnswer2 => 'hoofs',
2822             newPassword => 'moojolicious',
2823             newPasswordRepeat => 'moojolocious',
2824             });
2825              
2826             =cut
2827              
2828             sub forgotPassword {
2829             my ($self, $args) = @_;
2830             my $checkParams = {
2831             username => ['username', 1],
2832             emailAddress => ['string', 1],
2833             countryOfResidence => ['string',1],
2834             forgottenPasswordAnswer1 => ['string', 0],
2835             forgottenPasswordAnswer2 => ['string', 0],
2836             newPassword => ['password', 0],
2837             newPasswordRepeat => ['password', 0],
2838             };
2839             return 0 unless $self->_checkParams($checkParams, $args);
2840             $args->{exchangeId} = 3;
2841             if ($self->_doRequest('forgotPassword', $args)) {
2842             my $response = $self->{response}->{'soap:Body'}->{'n:forgotPasswordResponse'}->{'n:Result'};
2843             return 1 if exists $args->{forgottenPasswordAnswer1};
2844             return {
2845             question1 => $response->{'question1'}->{content},
2846             question2 => $response->{'question2'}->{content},
2847             };
2848             }
2849             return 0;
2850             }
2851              
2852             =head2 getAccountFunds
2853              
2854             Returns a hashref of the account funds betfair response. See L for details. Requires a hashref with the following parameters:
2855              
2856             =over
2857              
2858             =item *
2859              
2860             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2861              
2862             =back
2863              
2864             Example
2865              
2866             my $funds = $betfair->getAccountFunds({exchangeId => 1});
2867              
2868             =cut
2869              
2870             sub getAccountFunds {
2871             my ($self, $args) = @_;
2872             my $checkParams = {
2873             exchangeId => ['exchangeId', 1],
2874             };
2875             return 0 unless $self->_checkParams($checkParams, $args);
2876             if ($self->_doRequest('getAccountFunds', $args)) {
2877             return {
2878             availBalance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'availBalance'}->{content},
2879             balance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'balance'}->{content},
2880             exposure => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'exposure'}->{content},
2881             withdrawBalance => $self->{response}->{'soap:Body'}->{'n:getAccountFundsResponse'}->{'n:Result'}->{'withdrawBalance'}->{content}
2882             };
2883             }
2884             return 0;
2885             }
2886              
2887             =head2 getAccountStatement
2888              
2889             Returns an arrayref of hashes of account statement entries or 0 on failure. See L for further details. Requires:
2890              
2891             =over
2892              
2893             =item *
2894              
2895             startRecord : integer indicating the first record number to return. Record indexes are zero-based, hence 0 is the first record
2896              
2897             =item *
2898              
2899             recordCount : integer of the maximum number of records to return
2900              
2901             =item *
2902              
2903             startDate : date for which to return records on or after this date (a string in the XML datetime format see example)
2904              
2905             =item *
2906              
2907             endDate : date for which to return records on or before this date (a string in the XML datetime format see example)
2908              
2909             =item *
2910              
2911             itemsIncluded : string of the betfair AccountStatementIncludeEnum see L for details
2912              
2913             =item *
2914              
2915             exchangeId : integer representing the exchange id to connect to, either 1 (UK and rest of the world) or 2 (Australia)
2916              
2917             =back
2918              
2919             Example
2920              
2921             # return an account statement for all activity starting at record 1 up to 1000 records between 1st January 2013 and 16th June 2013
2922             my $statement = $betfair->getAccountStatement({
2923             startRecord => 0,
2924             recordCount => 1000,
2925             startDate => '2013-01-01T00:00:00.000Z',
2926             endDate => '2013-06-16T00:00:00.000Z',
2927             itemsIncluded => 'ALL',
2928             exchangeId => 2,
2929             });
2930              
2931             =cut
2932              
2933             sub getAccountStatement {
2934             my ($self, $args) = @_;
2935             my $checkParams = {
2936             startRecord => ['int', 1],
2937             recordCount => ['int', 1],
2938             startDate => ['date', 1],
2939             endDate => ['date', 1],
2940             itemsIncluded => ['accountStatementIncludeEnum', 1],
2941             exchangeId => ['exchangeId', 1],
2942             };
2943             return 0 unless $self->_checkParams($checkParams, $args);
2944             my @account_statement;
2945             if ($self->_doRequest('getAccountStatement', 1, $args)) {
2946             my $response =
2947             $self->_forceArray($self->{response}->{'soap:Body'}->{'n:getAccountStatementResponse'}->{'n:Result'}->{'items'}->{'n2:AccountStatementItem'});
2948             foreach (@{$response}) {
2949             push(@account_statement, {
2950             betType => $_->{'betType'}->{content},
2951             transactionId => $_->{'transactionId'}->{content},
2952             transactionType => $_->{'transactionType'}->{content},
2953             betSize => $_->{'betSize'}->{content},
2954             placedDate => $_->{'placedDate'}->{content},
2955             betId => $_->{'betId'}->{content},
2956             marketName => $_->{'marketName'}->{content},
2957             grossBetAmount => $_->{'grossBetAmount'}->{content},
2958             marketType => $_->{'marketType'}->{content},
2959             eventId => $_->{'eventId'}->{content},
2960             accountBalance => $_->{'accountBalance'}->{content},
2961             eventTypeId => $_->{'eventTypeId'}->{content},
2962             betCategoryType => $_->{'betCategoryType'}->{content},
2963             selectionName => $_->{'selectionName'}->{content},
2964             selectionId => $_->{'selectionId'}->{content},
2965             commissionRate => $_->{'commissionRate'}->{content},
2966             fullMarketName => $_->{'fullMarketName'}->{content},
2967             settledDate => $_->{'settledDate'}->{content},
2968             avgPrice => $_->{'avgPrice'}->{content},
2969             startDate => $_->{'startDate'}->{content},
2970             winLose => $_->{'winLose'}->{content},
2971             amount => $_->{'amount'}->{content}
2972             });
2973             }
2974             return \@account_statement;
2975             }
2976             return 0;
2977             }
2978              
2979             =head2 getPaymentCard
2980              
2981             Returns an arrayref of hashes of payment card or 0 on failure. See L for details. Does not require any parameters.
2982              
2983             Example
2984              
2985             my $cardDetails = $betfair->getPaymentCard;
2986              
2987             =cut
2988              
2989             sub getPaymentCard {
2990             my $self = shift;
2991             my $payment_cards = [];
2992             if ($self->_doRequest('getPaymentCard', {exchangeId => 3})) {
2993             my $response = $self->_forceArray(
2994             $self->{response}->{'soap:Body'}->{'n:getPaymentCardResponse'}->{'n:Result'}->{'paymentCardItems'}->{'n2:PaymentCard'});
2995             foreach (@{$response}) {
2996             $payment_cards = $self->_addPaymentCardLine($payment_cards, $_);
2997             }
2998             return $payment_cards;
2999             }
3000             return 0;
3001             }
3002              
3003             =head2 getSubscriptionInfo
3004              
3005             This service is not available with the free betfair API.
3006              
3007             Returns an arrayref of hashes of subscription or 0 on failure. See L for details. Does not require any parameters.
3008              
3009             Example
3010              
3011             my $subscriptionData = $betfair->getSubscriptionInfo;
3012              
3013             =cut
3014              
3015             sub getSubscriptionInfo {
3016             my ($self, $args) = @_;
3017             $args->{exchangeId} = 3;
3018             if ($self->_doRequest('getSubscriptionInfo', $args) ) {
3019             my $response = $self->{response}->{'soap:Body'}->{'n:getSubscriptionInfoResponse'}->{'n:Result'}->{subscriptions}->{'n2:Subscription'};
3020             my $subscriptionInfo = {
3021             billingAmount => $response->{billingAmount}->{content},
3022             billingDate => $response->{billingDate}->{content},
3023             billingPeriod => $response->{billingPeriod}->{content},
3024             productId => $response->{productId}->{content},
3025             productName => $response->{productName}->{content},
3026             subscribedDate => $response->{subscribedDate}->{content},
3027             status => $response->{status}->{content},
3028             vatEnabled => $response->{vatEnabled}->{content},
3029             setupCharge => $response->{setupCharge}->{content},
3030             setupChargeActive => $response->{setupChargeActive}->{content},
3031             services => [],
3032             };
3033             foreach (@{$response->{services}->{'n2:ServiceCall'}}) {
3034             push @{$subscriptionInfo->{services}}, {
3035             maxUsages => $_->{maxUsages}->{content},
3036             period => $_->{period}->{content},
3037             periodExpiry=> $_->{periodExpiry}->{content},
3038             serviceType => $_->{serviceType}->{content},
3039             usageCount => $_->{usageCount}->{content},
3040             };
3041             }
3042             return $subscriptionInfo;
3043             }
3044             return 0;
3045             }
3046              
3047             =head2 modifyPassword
3048              
3049             Changes the betfair account password. See L for details. Returns the betfair response as a hashref or 0 on failure. Requires:
3050              
3051             =over
3052              
3053             =item *
3054              
3055             password : string of the current account password
3056              
3057             =item *
3058              
3059             newPassword : string of the new account password
3060              
3061             =item *
3062              
3063             newPasswordRepeat : string of the new account password
3064              
3065             =back
3066              
3067             Example
3068              
3069             my $response = $betfair->modifyPassword({
3070             password => 'itsasecret',
3071             newPassword => 'moojolicious',
3072             newPasswordRepeat => 'moojolicious',
3073             });
3074              
3075             =cut
3076              
3077             sub modifyPassword {
3078             my ($self, $args) = @_;
3079             my $checkParams = {
3080             password => ['password', 1],
3081             newPassword => ['password', 1],
3082             newPasswordRepeat => ['password', 1],
3083             };
3084             return 0 unless $self->_checkParams($checkParams, $args);
3085             $args->{exchangeId} = 3;
3086             if ($self->_doRequest('modifyPassword', $args)) {
3087             return 1;
3088             }
3089             return 0;
3090             }
3091              
3092             =head2 modifyProfile
3093              
3094             Modifies the account profile details of the betfair account. See L for details. Returns 1 on success or 0 on failure. Requires a hashref with the following parameters:
3095              
3096             =over
3097              
3098             =item *
3099              
3100             password : string of the password for the betfair account
3101              
3102             =item *
3103              
3104             address1 : string of address line 1 (optional)
3105              
3106             =item *
3107              
3108             address2 : string of address line 2 (optional)
3109              
3110             =item *
3111              
3112             address3 : string of address line 3 (optional)
3113              
3114             =item *
3115              
3116             townCity : string of the town/city (optional)
3117              
3118             =item *
3119              
3120             countyState : string of the county or state - note for Australian accounts this must be a valid state (optional)
3121              
3122             =item *
3123              
3124             postCode : string of the postcode (aka zipcode). (optional)
3125              
3126             =item *
3127              
3128             countryOfResidence : string of the country of residence (optional)
3129              
3130             =item *
3131              
3132             homeTelephone : string of the home telephone number (optional)
3133              
3134             =item *
3135              
3136             workTelephone : string of the work telephone number (optional)
3137              
3138             =item *
3139              
3140             mobileTelephone : string of the mobile telephone number (optional)
3141              
3142             =item *
3143              
3144             emailAddress : string of the email address (optional)
3145              
3146             =item *
3147              
3148             timeZone : string of the timezone (optional)
3149              
3150             =item *
3151              
3152             depositLimit : integer of the deposite limit to set (optional)
3153              
3154             =item *
3155              
3156             depositLimitFrequency : string of the betfair GamcareLimitFreq enumerated type. See L for details (optional)
3157              
3158             =item *
3159              
3160             lossLimit : integer of the Gamcare loss limit for the account (optional)
3161              
3162             =item *
3163              
3164             lossLimitFrequency : string of the betfair GamcareLimitFreq enumerated type. See L for details (optional)
3165              
3166             =item *
3167              
3168             nationalIdentifier : string of the national identifier (optional)
3169              
3170             =back
3171              
3172             Example
3173              
3174             # update mobile number
3175             my $response = $betfair->modifyProfile({
3176             password => 'itsasecret',
3177             mobileTelephone => '07777777777',
3178             });
3179              
3180             =cut
3181              
3182              
3183             sub modifyProfile {
3184             my ($self, $args) = @_;
3185             my $checkParams = {
3186             password => ['password', 1],
3187             address1 => ['string', 0],
3188             address2 => ['string', 0],
3189             address3 => ['string', 0],
3190             townCity => ['string', 0],
3191             countyState => ['string', 0],
3192             postCode => ['string', 0],
3193             countryOfResidence => ['string', 0],
3194             homeTelephone => ['string', 0],
3195             workTelephone => ['string', 0],
3196             mobileTelephone => ['string', 0],
3197             emailAddress => ['string', 0],
3198             timeZone => ['string', 0],
3199             depositLimit => ['int', 0],
3200             depositLimitFrequency => ['gamcareLimitFreqEnum', 0],
3201             lossLimit => ['int', 0],
3202             lossLimitFrequency => ['gamcareLimitFreqEnum', 0],
3203             nationalIdentifier => ['string', 0],
3204             };
3205             return 0 unless $self->_checkParams($checkParams, $args);
3206             $args->{exchangeId} = 3;
3207             if ($self->_doRequest('modifyProfile', $args)) {
3208             return 1;
3209             }
3210             return 0;
3211             }
3212              
3213             =head2 retrieveLIMBMessage
3214              
3215             This service is not available with the betfair free API.
3216              
3217             Returns a hashref of the betfair response. See L for details. No parameters are required.
3218              
3219             Example
3220              
3221             my $limbMsg = $betfair->retrieveLimbMessage;
3222              
3223             =cut
3224              
3225             sub retrieveLIMBMessage {
3226             my $self = shift;
3227             if ($self->_doRequest('retrieveLIMBMessage', {exchangeId => 3})) {
3228             my $response = $self->{response}->{'soap:Body'}->{'n:retrieveLIMBMessageResponse'}->{'n:Result'};
3229             my $limbMsg = {
3230             totalMessageCount => $response->{totalMessageCount}->{content},
3231            
3232             retrievePersonalMessage => {
3233             message => $response->{retrievePersonalMessage}->{message}->{content},
3234             messageId => $response->{retrievePersonalMessage}->{messageId}->{content},
3235             enforceDate => $response->{retrievePersonalMessage}->{enforceDate}->{content},
3236             indicator => $response->{retrievePersonalMessage}->{indicator}->{content},
3237             },
3238              
3239             retrieveTCPrivacyPolicyChangeMessage => {
3240             reasonForChange => $response->{retrieveTCPrivacyPolicyChangeMessage}->{reasonForChange}->{content},
3241             messageId => $response->{retrieveTCPrivacyPolicyChangeMessage}->{messageId}->{content},
3242             enforceDate => $response->{retrieveTCPrivacyPolicyChangeMessage}->{enforceDate}->{content},
3243             indicator => $response->{retrieveTCPrivacyPolicyChangeMessage}->{indicator}->{content},
3244             },
3245             retrievePasswordChangeMessage => {
3246             messageId => $response->{retrievePasswordChangeMessage}->{messageId}->{content},
3247             enforceDate => $response->{retrievePasswordChangeMessage}->{enforceDate}->{content},
3248             indicator => $response->{retrievePasswordChangeMessage}->{indicator}->{content},
3249             },
3250             retrieveBirthDateCheckMessage => {
3251             messageId => $response->{retrieveBirthDateCheckMessage}->{messageId}->{content},
3252             enforceDate => $response->{retrieveBirthDateCheckMessage}->{enforceDate}->{content},
3253             indicator => $response->{retrieveBirthDateCheckMessage}->{indicator}->{content},
3254             birthDate => $response->{retrieveBirthDateCheckMessage}->{birthDate}->{content},
3255             },
3256             retrieveAddressCheckMessage => {
3257             messageId => $response->{retrieveAddressCheckMessage}->{messageId}->{content},
3258             enforceDate => $response->{retrieveAddressCheckMessage}->{enforceDate}->{content},
3259             indicator => $response->{retrieveAddressCheckMessage}->{indicator}->{content},
3260             address1 => $response->{retrieveAddressCheckMessage}->{address1}->{content},
3261             address2 => $response->{retrieveAddressCheckMessage}->{address2}->{content},
3262             address3 => $response->{retrieveAddressCheckMessage}->{address3}->{content},
3263             town => $response->{retrieveAddressCheckMessage}->{town}->{content},
3264             county => $response->{retrieveAddressCheckMessage}->{county}->{content},
3265             zipcode => $response->{retrieveAddressCheckMessage}->{zipcode}->{content},
3266             country => $response->{retrieveAddressCheckMessage}->{country}->{content},
3267             },
3268             retrieveContactDetailsCheckMessage => {
3269             messageId => $response->{retrieveContactDetailsCheckMessage}->{messageId}->{content},
3270             enforceDate => $response->{retrieveContactDetailsCheckMessage}->{enforceDate}->{content},
3271             indicator => $response->{retrieveContactDetailsCheckMessage}->{indicator}->{content},
3272             homeTelephone => $response->{retrieveContactDetailsCheckMessage}->{homeTelephone}->{content},
3273             workTelephone => $response->{retrieveContactDetailsCheckMessage}->{workTelephone}->{content},
3274             mobileTelephone => $response->{retrieveContactDetailsCheckMessage}->{mobileTelephone}->{content},
3275             emailAddress => $response->{retrieveContactDetailsCheckMessage}->{emailAddress}->{content},
3276             },
3277             retrieveChatNameChangeMessage => {
3278             messageId => $response->{retrieveChatNameChangeMessage}->{messageId}->{content},
3279             enforceDate => $response->{retrieveChatNameChangeMessage}->{enforceDate}->{content},
3280             indicator => $response->{retrieveChatNameChangeMessage}->{indicator}->{content},
3281             chatName => $response->{retrieveChatNameChangeMessage}->{chatName}->{content},
3282             },
3283             };
3284             my $billingAddressItems = $self->_forceArray(
3285             $response->{retrieveCardBillingAddressCheckItems}->{'n2:retrieveCarBillingAddressCheckLIMBMessage'});
3286             foreach (@{$billingAddressItems}) {
3287             push @{$limbMsg->{retrieveCardBillingAddressCheckItems}}, {
3288             messageId => $_->{messageId}->{content},
3289             enforceDate => $_->{enforceDate}->{content},
3290             indicator => $_->{indicator}->{content},
3291             nickName => $_->{nickName}->{content},
3292             cardShortNumber => $_->{cardShortNumber}->{content},
3293             address1 => $_->{address1}->{content},
3294             address2 => $_->{address2}->{content},
3295             address3 => $_->{address3}->{content},
3296             town => $_->{town}->{content},
3297             county => $_->{county}->{content},
3298             zipcode => $_->{zipcode}->{content},
3299             country => $_->{country}->{content},
3300             };
3301             }
3302             return $limbMsg;
3303             }
3304             return 0;
3305             }
3306              
3307             =head2 selfExclude
3308              
3309             WARNING - using this method will deactivate your betfair account for a minimum of 6 months. See L for details. Returns 1 on success or 0 on failure. Requires the following parameters in a hashref:
3310              
3311             =over
3312              
3313             =item *
3314              
3315             selfExclude : string boolean response (should be 'true' to succeed)
3316              
3317             =item *
3318              
3319             password : string of the betfair account password
3320              
3321             =back
3322              
3323             Example
3324              
3325             $excludeResult = $betfair->selfExclude({
3326             selfExclude => 'true',
3327             password => 'itsasecret',
3328             });
3329              
3330             =cut
3331              
3332             sub selfExclude {
3333             my ($self, $args) = @_;
3334             my $checkParams = {
3335             password => ['password', 1],
3336             selfExclude => ['boolean', 1],
3337             };
3338             return 0 unless $self->_checkParams($checkParams, $args);
3339             $args->{exchangeId} = 3;
3340             if ($self->_doRequest('selfExclude', $args)) {
3341             return 1;
3342             }
3343             return 0;
3344             }
3345              
3346             =head2 setChatName
3347              
3348             This service is not available with the free betfair API, nor with the paid personal betfair API.
3349              
3350             Sets the chat name of the betfair account. See L for details. Returns 1 on success or 0 on failure. Requires the following parameters in a hashref:
3351              
3352             =over
3353              
3354             =item *
3355              
3356             chatName : string of the desired chatname
3357              
3358             =item *
3359              
3360             password : string of the betfair account password
3361              
3362             =back
3363              
3364             Example
3365              
3366             $excludeResult = $betfair->setChatName({
3367             chatName => 'sillymoose',
3368             password => 'itsasecret',
3369             });
3370              
3371             =cut
3372              
3373             sub setChatName {
3374             my ($self, $args) = @_;
3375             my $checkParams = {
3376             password => ['password', 1],
3377             chatName => ['string', 1],
3378             };
3379             return 0 unless $self->_checkParams($checkParams, $args);
3380             $args->{exchangeId} = 3;
3381             if ($self->_doRequest('setChatName', $args)) {
3382             return 1;
3383             }
3384             return 0;
3385             }
3386              
3387             =head2 submitLIMBMessage
3388              
3389             This service is not available with the betfair free API.
3390              
3391             Submits a LIMB message to the betfair API. See L for details. Returns 1 on success or 0 on failure. betfair returns additional validation error information on failure, so be sure to check the error message using the getError method. Requires a hashref with the following parameters:
3392              
3393             =over
3394              
3395             =item *
3396              
3397             password : string of the betfair account password
3398              
3399             =item *
3400              
3401             submitPersonalMessage : a hashref containing the following key / pair values (optional):
3402              
3403             =over 8
3404              
3405             =item *
3406              
3407             messageId : integer of the message Id
3408              
3409             =item *
3410              
3411             acknowledgement : string 'Y'
3412              
3413             =back
3414              
3415             =item *
3416              
3417             submitTCPrivacyPolicyChangeMessage : a hashref containing the following key / value pairs (optional):
3418              
3419             =over 8
3420              
3421             =item *
3422              
3423             messageId : integer of the message Id
3424              
3425             =item *
3426              
3427             tCPrivacyPolicyChangeAcceptance : string 'Y'
3428              
3429             =back
3430              
3431             =item *
3432              
3433             submitPasswordChangeMessage : a hashref containing the following key / value pairs (optional):
3434              
3435             =over 8
3436              
3437             =item *
3438              
3439             messageId : integer of the message Id
3440              
3441             =item *
3442              
3443             newPassword : string of the new password
3444              
3445             =item *
3446              
3447             newPasswordRepeat : string of the new password
3448              
3449             =back
3450              
3451             =item *
3452              
3453             submitBirthDateCheckMessage : a hashref containing the following key / value pairs (optional):
3454              
3455             =over 8
3456              
3457             =item *
3458              
3459             messageId : integer of the message Id
3460              
3461             =item *
3462              
3463             detailsCorrect : string of either 'Y' or 'N'
3464              
3465             =item *
3466              
3467             correctBirthDate : string of the correct birthdate - should be a valid XML datetime format
3468              
3469             =back
3470              
3471             =item *
3472              
3473             submitAddressCheckMessage : a hashref containing the following key / value pairs (optional):
3474              
3475             =over 8
3476              
3477             =item *
3478              
3479             messageId : integer of the message Id
3480              
3481             =item *
3482              
3483             detailsCorrect : string of either 'Y' or 'N'
3484              
3485             =item *
3486              
3487             newAddress1 : string of the first line of the address
3488              
3489             =item *
3490              
3491             newAddress2 : string of the second line of the address
3492              
3493             =item *
3494              
3495             newAddress3 : string of the third line of the address
3496              
3497             =item *
3498              
3499             newTown: string of the town of the address
3500              
3501             =item *
3502              
3503             newZipCode: string of the postal code of the address
3504              
3505             =item *
3506              
3507             newCountry: string of the the Country of the address
3508              
3509             =back
3510              
3511             submitContactDetailsCheckMessage: a hashref containing the following key / value pairs (optional):
3512              
3513             =over 8
3514              
3515             =item *
3516              
3517             messageId : integer of the message Id
3518              
3519             =item *
3520              
3521             detailsCorrect : string of either 'Y' or 'N'
3522              
3523             =item *
3524              
3525             newHomeTelephone : string of the new home telephone number
3526              
3527             =item *
3528              
3529             newWorkTelephone : string of the new work telephone number
3530              
3531             =item *
3532              
3533             newMobileTelephone : string of the new mobile telephone number
3534              
3535             =item *
3536              
3537             newEmailAddress : string of the new email address
3538              
3539             =back
3540              
3541             =item *
3542              
3543             submitChatNameChangeMessage : a hashref containing the following key / value pairs (optional):
3544              
3545             =over 8
3546              
3547             =item *
3548              
3549             messageId : integer of the message Id
3550              
3551             =item *
3552              
3553             newChatName : string of the new chat name
3554              
3555             =back
3556              
3557             =item *
3558              
3559             submitCardBillingAddressCheckItems : an arrayref of hashrefs containing the following key / value pairs (optional):
3560              
3561             =over 8
3562              
3563             =item *
3564              
3565             messageId : integer of the message Id
3566              
3567             =item *
3568              
3569             detailsCorrect : string of either 'Y' or 'N'
3570              
3571             =item *
3572              
3573             nickName : string of the card nick name (8 characters or less)
3574              
3575             =item *
3576              
3577             newAddress1 : string of the first line of the address
3578              
3579             =item *
3580              
3581             newAddress2 : string of the second line of the address
3582              
3583             =item *
3584              
3585             newAddress3 : string of the third line of the address
3586              
3587             =item *
3588              
3589             newTown: string of the town of the address
3590              
3591             =item *
3592              
3593             newZipCode: string of the postal code of the address
3594              
3595             =item *
3596              
3597             newCountry: string of the the Country of the address
3598              
3599             =back
3600              
3601             =back
3602              
3603             Example
3604              
3605             my $limbMsg = $betfair->submitLimbMessage({
3606             password => 'itsasecret',
3607             submitPersonalMessage => { messageId => 123456789,
3608             acknowledgement=> 'Y',
3609             },
3610             });
3611              
3612             =cut
3613              
3614             sub submitLIMBMessage {
3615             my ($self, $args) = @_;
3616             my $checkParams = {
3617             password => ['password', 1],
3618             submitPersonalMessage => ['hash', 0],
3619             submitTCPrivacyPolicyChangeMessage => ['hash', 0],
3620             submitPasswordChangeMessage => ['hash', 0],
3621             submitBirthDateCheckMessage => ['hash', 0],
3622             submitAddressCheckMessage => ['hash', 0],
3623             submitContactDetailsCheckMessage => ['hash', 0],
3624             submitChatNameChangeMessage => ['hash', 0],
3625             submitCardBillingAddressCheckItems => ['hash', 0],
3626             };
3627             return 0 unless $self->_checkParams($checkParams, $args);
3628             $args->{exchangeId} = 3;
3629             if ($self->_doRequest('submitLIMBMessage', $args) ) {
3630             return 1;
3631             }
3632             # add any validation errors to the header error message so that user can retrieve the information using getError
3633              
3634             return 0 unless exists $self->{response}->{'soap:Body'}->{'n:submitLIMBMessageResponse'}->{'n:Result'}->{validationErrors};
3635             my $response = $self->_forceArray(
3636             $self->{response}->{'soap:Body'}->{'n:submitLIMBMessageResponse'}->{'n:Result'});
3637             my $validationErrors;
3638             foreach (@{$response}) {
3639             $validationErrors .= ' ' . $_->{content};
3640             }
3641             $self->{headerError} .= ' ' . $validationErrors;
3642             return 0;
3643             }
3644              
3645             =head2 transferFunds
3646              
3647             Transfers funds between the UK and Australian wallets. See L for details. Returns a hashref of the betfair response or 0 on failure. Requires the following parameters in a hashref:
3648              
3649             =over
3650              
3651             =item *
3652              
3653             sourceWalletId : integer either: 1 for UK wallet or 2 for the Australian wallet
3654              
3655             =item *
3656              
3657             targetWalletId : integer either: 1 for UK wallet or 2 for the Australian wallet
3658              
3659             =item *
3660              
3661             amount : number representing the amount of money to transfer between wallets
3662              
3663             =back
3664              
3665             Example
3666              
3667             # transfer 15 from the UK wallet to the Australian wallet
3668             $excludeResult = $betfair->transferFunds({
3669             sourceWalletId => 1,
3670             targetWalletId => 2,
3671             amount => 15.0,
3672             });
3673              
3674             =cut
3675              
3676             sub transferFunds {
3677             my ($self, $args) = @_;
3678             my $checkParams = {
3679             sourceWalletId => ['int', 1],
3680             targetWalletId => ['int', 1],
3681             amount => ['decimal', 1],
3682             };
3683             return 0 unless $self->_checkParams($checkParams, $args);
3684             $args->{exchangeId} = 3;
3685             if ($self->_doRequest('transferFunds', $args)) {
3686             my $response = $self->{response}->{'soap:Body'}->{'n:transferFundsResponse'}->{'n:Result'};
3687             return {
3688             monthlyDepositTotal => $response->{monthlyDepositTotal}->{content},
3689             };
3690             }
3691             return 0;
3692             }
3693              
3694             =head2 updatePaymentCard
3695              
3696             Updates a payment card on your betfair account. Returns a hashref betfair response or 0 on failure. See L. Requires:
3697              
3698             =over
3699              
3700             =item *
3701              
3702             cardStatus : string of a valid betfair paymentCardStatusEnum, either 'LOCKED' or 'UNLOCKED'
3703              
3704             =item *
3705              
3706             startDate : string of the card start date, optional depending on type of card
3707              
3708             =item *
3709              
3710             expiryDate : string of the card expiry date
3711              
3712             =item *
3713              
3714             issueNumber : string of the issue number or NULL if the cardType is not Solo or Switch
3715              
3716             =item *
3717              
3718             nickName : string of the card nickname must be less than 9 characters
3719              
3720             =item *
3721              
3722             password : string of the betfair account password
3723              
3724             =item *
3725              
3726             address1 : string of the first line of the address for the payment card
3727              
3728             =item *
3729              
3730             address2 : string of the second line of the address for the payment card
3731              
3732             =item *
3733              
3734             address3 : string of the third line of the address for the payment card (optional)
3735              
3736             =item *
3737              
3738             address4 : string of the fourth line of the address for the payment card (optional)
3739              
3740             =item *
3741              
3742             town : string of the town for the payment card
3743              
3744             =item *
3745              
3746             county : string of the county for the payment card
3747              
3748             =item *
3749              
3750             zipCode : string of the zip / postal code for the payment card
3751              
3752             =item *
3753              
3754             country : string of the country for the payment card
3755              
3756             =back
3757              
3758             Example
3759              
3760             my $updatePaymentCardResponse = $betfair->updatePaymentCard({
3761             cardStatus => 'UNLOCKED',
3762             startDate => '0113',
3763             expiryDate => '0116',
3764             issueNumber => 'NULL',
3765             billingName => 'The Sillymoose',
3766             nickName => 'democard',
3767             password => 'password123',
3768             address1 => 'Tasty bush',
3769             address2 => 'Mountain Plains',
3770             town => 'Hoofton',
3771             zipCode => 'MO13FR',
3772             county => 'Mooshire',
3773             country => 'UK',
3774             });
3775              
3776             =cut
3777              
3778             sub updatePaymentCard {
3779             my ($self, $args) = @_;
3780             my $checkParams = {
3781             cardStatus => ['cardStatusEnum', 1],
3782             startDate => ['cardDate', 1],
3783             expiryDate => ['cardDate', 1],
3784             issueNumber => ['int', 1],
3785             billingName => ['string', 1],
3786             nickName => ['string9', 1],
3787             password => ['password', 1],
3788             address1 => ['string', 1],
3789             address2 => ['string', 0],
3790             address3 => ['string', 0],
3791             address4 => ['string', 0],
3792             town => ['string', 1],
3793             zipCode => ['string', 1],
3794             county => ['string', 1],
3795             country => ['string', 1],
3796             };
3797             return 0 unless $self->_checkParams($checkParams, $args);
3798             $args->{exchangeId} = 3;
3799             if ($self->_doRequest('updatePaymentCard', $args) ) {
3800             my $response = $self->{response}->{'soap:Body'}->{'n:updatePaymentCardResponse'}->{'n:Result'};
3801             return {
3802             nickName => $response->{nickName}->{content},
3803             billingName => $response->{billingName}->{content},
3804             cardType => $response->{cardType}->{content},
3805             expiryDate => $response->{expiryDate}->{content},
3806             startDate => $response->{startDate}->{content},
3807             address1 => $response->{address1}->{content},
3808             address2 => $response->{address2}->{content},
3809             address3 => $response->{address3}->{content},
3810             address4 => $response->{address4}->{content},
3811             zipCode => $response->{zipCode}->{content},
3812             country => $response->{country}->{content},
3813             };
3814             }
3815             return 0;
3816             }
3817              
3818             =head2 viewProfile
3819              
3820             Returns a hashref betfair response or 0 on failure. See L. Requires no parameters.
3821              
3822             Example
3823              
3824             my $profile = $betfair->viewProfile;
3825              
3826             =cut
3827              
3828             sub viewProfile {
3829             my $self = shift;
3830             if ($self->_doRequest('viewProfile', {exchangeId => 3})) {
3831             my $response = $self->{response}->{'soap:Body'}->{'n:viewProfileResponse'}->{'n:Result'};
3832             return {
3833             title => $response->{title}->{content},
3834             firstName => $response->{firstName}->{content},
3835             surname => $response->{surname}->{content},
3836             userName => $response->{userName}->{content},
3837             forumName => $response->{forumName}->{content},
3838             address1 => $response->{address1}->{content},
3839             address2 => $response->{address2}->{content},
3840             address3 => $response->{address3}->{content},
3841             townCity => $response->{townCity}->{content},
3842             countyState => $response->{countyState}->{content},
3843             postCode => $response->{postCode}->{content},
3844             countryOfResidence => $response->{countryOfResidence}->{content},
3845             homeTelephone => $response->{homeTelephone}->{content},
3846             workTelephone => $response->{workTelephone}->{content},
3847             mobileTelephone => $response->{mobileTelephone}->{content},
3848             emailAddress => $response->{emailAddress}->{content},
3849             timeZone => $response->{timeZone}->{content},
3850             currency => $response->{currency}->{content},
3851             gamecareLimit => $response->{gamcareLimit}->{content},
3852             gamcareFrequency => $response->{gamcareFrequency}->{content},
3853             gamecareLossLimit => $response->{gamcareLossLimit}->{content},
3854             gamcareLossLimitFrequency=> $response->{gamcareLossLimitFrequency}->{content},
3855             };
3856             }
3857             return 0;
3858             }
3859              
3860             =head2 viewProfileV2
3861              
3862             Returns a hashref betfair response or 0 on failure. See L. Requires no parameters.
3863              
3864             Example
3865              
3866             my $profile = $betfair->viewProfileV2;
3867              
3868             =cut
3869              
3870             sub viewProfileV2 {
3871             my $self = shift;
3872             if ($self->_doRequest('viewProfileV2', {requestVersion => 'V1',
3873             exchangeId => 3,
3874             })) {
3875             my $response = $self->{response}->{'soap:Body'}->{'n:viewProfileV2Response'}->{'n:Result'};
3876             return {
3877             title => $response->{title}->{content},
3878             firstName => $response->{firstName}->{content},
3879             surname => $response->{surname}->{content},
3880             userName => $response->{userName}->{content},
3881             forumName => $response->{forumName}->{content},
3882             address1 => $response->{address1}->{content},
3883             address2 => $response->{address2}->{content},
3884             address3 => $response->{address3}->{content},
3885             townCity => $response->{townCity}->{content},
3886             countyState => $response->{countyState}->{content},
3887             postCode => $response->{postCode}->{content},
3888             countryOfResidence => $response->{countryOfResidence}->{content},
3889             homeTelephone => $response->{homeTelephone}->{content},
3890             workTelephone => $response->{workTelephone}->{content},
3891             mobileTelephone => $response->{mobileTelephone}->{content},
3892             emailAddress => $response->{emailAddress}->{content},
3893             timeZone => $response->{timeZone}->{content},
3894             currency => $response->{currency}->{content},
3895             gamecareLimit => $response->{gamcareLimit}->{content},
3896             gamcareFrequency => $response->{gamcareFrequency}->{content},
3897             gamecareLossLimit => $response->{gamcareLossLimit}->{content},
3898             gamcareLossLimitFrequency=> $response->{gamcareLossLimitFrequency}->{content},
3899             tAN => $response->{tAN}->{content},
3900             referAndEarnCode => $response->{referAndEarnCode}->{content},
3901             earthportId => $response->{earthportId}->{content},
3902             kYCStatus => $response->{kYCStatus}->{content},
3903             nationalIdentifier => $response->{nationalIdentifier}->{content},
3904             };
3905             }
3906             return 0;
3907             }
3908              
3909             =head2 viewReferAndEarn
3910              
3911             Returns a hashref containing the betfair account's refer and earn code or 0 on failure. See L for details. Requires no parameters.
3912              
3913             Example
3914              
3915             my $referAndEarnCode = $betfair->viewReferAndEarn;
3916              
3917             =cut
3918              
3919             sub viewReferAndEarn {
3920             my $self = shift;
3921             if ($self->_doRequest('viewReferAndEarn', {exchangeId => 3})) {
3922             my $response = $self->{response}->{'soap:Body'}->{'n:viewReferAndEarnResponse'}->{'n:Result'};
3923             return {
3924             referAndEarnCode => $response->{'referAndEarnCode'}->{content},
3925             };
3926             }
3927             return 0;
3928             }
3929              
3930             =head2 withdrawToPaymentCard
3931              
3932             Withdraws money from your betfair account to the payment card specified. Returns a hashref of the withdraw response from betfair or 0 on failure. See L for details. Requires:
3933              
3934             =over
3935              
3936             =item *
3937              
3938             amount : number representing the amount of money to withdraw
3939              
3940             =item *
3941              
3942             cardIdentifier : string of the nickname of the payment card
3943              
3944             =item *
3945              
3946             password : string of your betfair password
3947              
3948             =back
3949              
3950             Example
3951              
3952             my $withdrawalResult = $betfair->withdrawToPaymentCard({
3953             amount => 10,
3954             cardIdentifier => 'checking',
3955             password => 'password123',
3956             });
3957              
3958             =cut
3959              
3960             sub withdrawToPaymentCard {
3961             my ($self, $args) = @_;
3962             my $checkParams = {
3963             amount => ['decimal', 1],
3964             cardIdentifier => ['string9', 1],
3965             password => ['password', 1],
3966             };
3967             return 0 unless $self->_checkParams($checkParams, $args);
3968             $args->{exchangeId} = 3;
3969             if ($self->_doRequest('withdrawToPaymentCard', $args) ) {
3970             my $response = $self->{response}->{'soap:Body'}->{'n:withdrawToPaymentCardResponse'}->{'n:Result'};
3971             return {
3972             amountWithdrawn => $response->{'amountWithdrawn'}->{content},
3973             maxAmount => $response->{'maxAmount'}->{content}
3974             };
3975             }
3976             return 0;
3977             }
3978              
3979             =head1 INTERNAL METHODS
3980              
3981             =head2 _doRequest
3982              
3983             Processes requests to and from the betfair API.
3984              
3985             =cut
3986              
3987             sub _doRequest {
3988             my ($self, $action, $params) = @_;
3989              
3990             # get the server url and remove the server id from $params
3991             my $server = $params->{exchangeId};
3992             my $uri = $self->_getServerURI($server);
3993             delete $params->{exchangeId};
3994              
3995             # clear data from previous request
3996             $self->_clearData;
3997            
3998             # add header to $params
3999             $params->{header}->{sessionToken} = $self->{sessionToken} if defined $self->{sessionToken};
4000             $params->{header}->{clientStamp} = 0;
4001              
4002             # build xml message
4003             $self->{xmlsent} = WWW::betfair::Template::populate($uri, $action, $params);
4004              
4005             # save response, session token and error as attributes
4006             my $uaResponse = WWW::betfair::Request::new_request($uri, $action, $self->{xmlsent});
4007             $self->{xmlreceived} = $uaResponse->decoded_content(charset => 'none');
4008             $self->{response} = eval {XMLin($self->{xmlreceived})};
4009             if ($@) {
4010             croak 'error parsing betfair XML response ' . $@;
4011             }
4012             if ($self->{response}){
4013              
4014             $self->{sessionToken}
4015             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'header'}->{'sessionToken'}->{content};
4016            
4017             $self->{headerError}
4018             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'header'}->{'errorCode'}->{content}
4019             || 'OK';
4020              
4021             $self->{bodyError}
4022             = $self->{response}->{'soap:Body'}->{'n:'.$action.'Response'}->{'n:Result'}->{'errorCode'}->{content}
4023             || 'OK';
4024             return 1 if $self->getError eq 'OK';
4025             }
4026             return 0;
4027             }
4028              
4029             =head2 _getServerURI
4030              
4031             Returns the URI for the target betfair server depending on whether it is an exchange server (1 and 2) or the global server.
4032              
4033             =cut
4034              
4035             sub _getServerURI {
4036             my ($self, $server) = @_;
4037             given($server) {
4038             when (/1/) { return 'https://api.betfair.com/exchange/v5/BFExchangeService'}
4039             when (/2/) { return 'https://api-au.betfair.com/exchange/v5/BFExchangeService'}
4040             default { return 'https://api.betfair.com/global/v3/BFGlobalService'}
4041             }
4042             }
4043              
4044              
4045             =head2 _sortArrayRef
4046              
4047             Returns a sorted arrayref based on price.
4048              
4049             =cut
4050              
4051             sub _sortArrayRef {
4052             my $array_ref = shift;
4053             if (ref($array_ref) eq 'ARRAY'){
4054             return sort { $b->{price} <=> $a->{price} } @$array_ref;
4055             }
4056             return $array_ref;
4057             }
4058              
4059             =head2 _addPaymentCardLine
4060              
4061             Pushes a hashref of payment card key / value pairs into an arrayref and returns the result.
4062              
4063             =cut
4064              
4065             sub _addPaymentCardLine {
4066             my ($self, $payment_card, $line_to_be_added) = @_;
4067             push(@{$payment_card}, {
4068             countryCodeIso3 => $line_to_be_added->{'billingCountryIso3'}->{content},
4069             billingAddress1 => $line_to_be_added->{'billingAddress1'}->{content},
4070             billingAddress2 => $line_to_be_added->{'billingAddress2'}->{content},
4071             billingAddress3 => $line_to_be_added->{'billingAddress3'}->{content},
4072             billingAddress4 => $line_to_be_added->{'billingAddress4'}->{content},
4073             cardType => $line_to_be_added->{'cardType'}->{content},
4074             issuingCountryIso3 => $line_to_be_added->{'issuingCountryIso3'}->{content},
4075             totalWithdrawals => $line_to_be_added->{'totalWithdrawals'}->{content},
4076             expiryDate => $line_to_be_added->{'expiryDate'}->{content},
4077             nickName => $line_to_be_added->{'nickName'}->{content},
4078             cardStatus => $line_to_be_added->{'cardStatus'}->{content},
4079             issueNumber => $line_to_be_added->{'issueNumber'}->{content},
4080             country => $line_to_be_added->{'country'}->{content},
4081             county => $line_to_be_added->{'county'}->{content},
4082             billingName => $line_to_be_added->{'billingName'}->{content},
4083             town => $line_to_be_added->{'town'}->{content},
4084             postcode => $line_to_be_added->{'postcode'}->{content},
4085             netDeposits => $line_to_be_added->{'netDeposits'}->{content},
4086             cardShortNumber => $line_to_be_added->{'cardShortNumber'}->{content},
4087             totalDeposits => $line_to_be_added->{'totalDeposits'}->{content}
4088             });
4089             return $payment_card;
4090             }
4091              
4092             =head2 _forceArray
4093              
4094             Receives a reference variable and if the data is not an array, returns a single-element arrayref. Else returns the data as received.
4095              
4096             =cut
4097              
4098             sub _forceArray {
4099             my ($self, $data) = @_;
4100             return ref($data) eq 'ARRAY' ? $data : [$data];
4101             }
4102              
4103             =head2 _checkParams
4104              
4105             Receives an hashref of parameter types and a hashref of arguments. Checks that all mandatory arguments are present using _checkParam and that no additional parameters exist in the hashref.
4106              
4107             =cut
4108              
4109             sub _checkParams {
4110             my ($self, $paramChecks, $args) = @_;
4111              
4112             # check no rogue arguments have been included in parameters
4113             foreach my $paramName (keys %{$args}) {
4114             if (not exists $paramChecks->{$paramName}) {
4115             $self->{headerError} = "Error: unexpected parameter $paramName is not a correct argument for the method called.";
4116             return 0;
4117             }
4118             # if exists now check that the type is correct
4119             else {
4120             return 0 unless $self->_checkParam( $paramChecks->{$paramName}->[0],
4121             $args->{$paramName});
4122             }
4123             }
4124             # check all mandatory parameters are present
4125             foreach my $paramName (keys %{$paramChecks}){
4126             if ($paramChecks->{$paramName}->[1]){
4127             unless (exists $args->{$paramName}) {
4128             $self->{headerError} = "Error: missing mandatory parameter $paramName.";
4129             return 0;
4130             }
4131             }
4132             }
4133             return 1;
4134             }
4135              
4136             =head2 _checkParam
4137              
4138             Checks the parameter using the TypeCheck.pm object, returns 1 on success and 0 on failure.
4139              
4140             =cut
4141              
4142             sub _checkParam {
4143             my ($self, $type, $value) = @_;
4144             unless($self->{type}->checkParameter($type, $value)) {
4145             $self->{headerError} = "Error: message not sent as parameter $value failed the type requirements check for $type. Check the documentation at the command line: perldoc WWW::betfair::TypeCheck";
4146             return 0;
4147             }
4148             return 1;
4149             }
4150              
4151             =head2 _clearData
4152              
4153             Sets all message related object attributes to null - this is so that the error message from the previous API call is not mis-read as relevant to the current call.
4154              
4155             =cut
4156              
4157             sub _clearData {
4158             my $self = shift;
4159             $self->{xmlsent} = undef;
4160             $self->{xmlreceived} = undef;
4161             $self->{headerError} = undef;
4162             $self->{bodyError} = undef;
4163             $self->{response} = {};
4164             return 1;
4165             }
4166              
4167              
4168             1;
4169              
4170             =head1 AUTHOR
4171              
4172             David Farrell, C<< >>, L
4173              
4174             =head1 BUGS
4175              
4176             Please report any bugs or feature requests to C, or through
4177             the web interface at L. I will be notified, and then you'll
4178             automatically be notified of progress on your bug as I make changes.
4179              
4180             =head1 SUPPORT
4181              
4182             You can find documentation for this module with the perldoc command.
4183              
4184             perldoc WWW::betfair
4185              
4186              
4187             You can also look for information at:
4188              
4189             =over
4190              
4191             =item * RT: CPAN's request tracker (report bugs here)
4192              
4193             L
4194              
4195             =item * AnnoCPAN: Annotated CPAN documentation
4196              
4197             L
4198              
4199             =item * CPAN Ratings
4200              
4201             L
4202              
4203             =item * Search CPAN
4204              
4205             L
4206              
4207             =back
4208              
4209             =head1 ACKNOWLEDGEMENTS
4210              
4211             This project was inspired by the L Perl project. Although L uses a different approach, the betfair free project was a useful point of reference at inception. Thanks guys!
4212              
4213             Thanks to L for creating the exchange and API.
4214              
4215             =head1 LICENSE AND COPYRIGHT
4216              
4217             Copyright 2013 David Farrell.
4218              
4219             This program is free software; you can redistribute it and/or modify it
4220             under the terms of either: the GNU General Public License as published
4221             by the Free Software Foundation; or the Artistic License.
4222              
4223             See http://dev.perl.org/licenses/ for more information.
4224              
4225             =cut