Skip to content

Commit 93118ad

Browse files
Merge pull request #162 from riyazpanjwani/main
Adding support for Get App Transaction Info endpoint
2 parents c9e596e + eccdb46 commit 93118ad

File tree

8 files changed

+219
-20
lines changed

8 files changed

+219
-20
lines changed

appstoreserverlibrary/api_client.py

Lines changed: 52 additions & 20 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2025 Apple Inc. Licensed under MIT License.
2+
from typing import Optional
3+
4+
from attr import define
5+
import attr
6+
7+
@define
8+
class AppTransactionInfoResponse:
9+
"""
10+
A response that contains signed app transaction information for a customer.
11+
12+
https://developer.apple.com/documentation/appstoreserverapi/apptransactioninforesponse
13+
"""
14+
15+
signedAppTransactionInfo: Optional[str] = attr.ib(default=None)
16+
"""
17+
A customer’s app transaction information, signed by Apple, in JSON Web Signature (JWS) format.
18+
19+
https://developer.apple.com/documentation/appstoreserverapi/jwsapptransaction
20+
"""
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"errorCode": 4040019,
3+
"errorMessage": "No AppTransaction exists for the customer."
4+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"signedAppTransactionInfo": "signed_app_transaction_info_value"
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"errorCode": 4000006,
3+
"errorMessage": "Invalid transaction id."
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"errorCode": 4040010,
3+
"errorMessage": "Transaction id not found."
4+
}

tests/test_api_client.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,71 @@ def test_delete_default_message(self):
654654
None)
655655
client.delete_default_message('com.example.product', 'en-US')
656656

657+
def test_get_app_transaction_info_success(self):
658+
client = self.get_client_with_body_from_file('tests/resources/models/appTransactionInfoResponse.json',
659+
'GET',
660+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/1234',
661+
{},
662+
None)
663+
664+
app_transaction_info_response = client.get_app_transaction_info('1234')
665+
666+
self.assertIsNotNone(app_transaction_info_response)
667+
self.assertEqual('signed_app_transaction_info_value', app_transaction_info_response.signedAppTransactionInfo)
668+
669+
def test_get_app_transaction_info_invalid_transaction_id(self):
670+
client = self.get_client_with_body_from_file('tests/resources/models/invalidTransactionIdError.json',
671+
'GET',
672+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/invalid_id',
673+
{},
674+
None,
675+
400)
676+
try:
677+
client.get_app_transaction_info('invalid_id')
678+
except APIException as e:
679+
self.assertEqual(400, e.http_status_code)
680+
self.assertEqual(4000006, e.raw_api_error)
681+
self.assertEqual(APIError.INVALID_TRANSACTION_ID, e.api_error)
682+
self.assertEqual("Invalid transaction id.", e.error_message)
683+
return
684+
self.assertFalse(True)
685+
686+
def test_get_app_transaction_info_app_transaction_does_not_exist(self):
687+
client = self.get_client_with_body_from_file('tests/resources/models/appTransactionDoesNotExistError.json',
688+
'GET',
689+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/nonexistent_id',
690+
{},
691+
None,
692+
404)
693+
try:
694+
client.get_app_transaction_info('nonexistent_id')
695+
except APIException as e:
696+
self.assertEqual(404, e.http_status_code)
697+
self.assertEqual(4040019, e.raw_api_error)
698+
self.assertEqual(APIError.APP_TRANSACTION_DOES_NOT_EXIST_ERROR, e.api_error)
699+
self.assertEqual("No AppTransaction exists for the customer.", e.error_message)
700+
return
701+
702+
self.assertFalse(True)
703+
704+
def test_get_app_transaction_info_transaction_id_not_found(self):
705+
client = self.get_client_with_body_from_file('tests/resources/models/transactionIdNotFoundError.json',
706+
'GET',
707+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/not_found_id',
708+
{},
709+
None,
710+
404)
711+
try:
712+
client.get_app_transaction_info('not_found_id')
713+
except APIException as e:
714+
self.assertEqual(404, e.http_status_code)
715+
self.assertEqual(4040010, e.raw_api_error)
716+
self.assertEqual(APIError.TRANSACTION_ID_NOT_FOUND, e.api_error)
717+
self.assertEqual("Transaction id not found.", e.error_message)
718+
return
719+
720+
self.assertFalse(True)
721+
657722

658723
def get_signing_key(self):
659724
return read_data_from_binary_file('tests/resources/certs/testSigningKey.p8')

tests/test_api_client_async.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from appstoreserverlibrary.api_client import APIError, APIException, AsyncAppStoreServerAPIClient, GetTransactionHistoryVersion
99
from appstoreserverlibrary.models.AccountTenure import AccountTenure
10+
from appstoreserverlibrary.models.AppTransactionInfoResponse import AppTransactionInfoResponse
1011
from appstoreserverlibrary.models.AutoRenewStatus import AutoRenewStatus
1112
from appstoreserverlibrary.models.ConsumptionRequest import ConsumptionRequest
1213
from appstoreserverlibrary.models.ConsumptionStatus import ConsumptionStatus
@@ -657,6 +658,72 @@ async def test_delete_default_message(self):
657658
{},
658659
None)
659660
await client.delete_default_message('com.example.product', 'en-US')
661+
662+
async def test_get_app_transaction_info_success(self):
663+
client = self.get_client_with_body_from_file('tests/resources/models/appTransactionInfoResponse.json',
664+
'GET',
665+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/1234',
666+
{},
667+
None)
668+
669+
app_transaction_info_response = await client.get_app_transaction_info('1234')
670+
671+
self.assertIsNotNone(app_transaction_info_response)
672+
self.assertEqual('signed_app_transaction_info_value', app_transaction_info_response.signedAppTransactionInfo)
673+
674+
async def test_get_app_transaction_info_invalid_transaction_id(self):
675+
client = self.get_client_with_body_from_file('tests/resources/models/invalidTransactionIdError.json',
676+
'GET',
677+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/invalid_id',
678+
{},
679+
None,
680+
400)
681+
try:
682+
await client.get_app_transaction_info('invalid_id')
683+
except APIException as e:
684+
self.assertEqual(400, e.http_status_code)
685+
self.assertEqual(4000006, e.raw_api_error)
686+
self.assertEqual(APIError.INVALID_TRANSACTION_ID, e.api_error)
687+
self.assertEqual("Invalid transaction id.", e.error_message)
688+
return
689+
690+
self.assertFalse(True)
691+
692+
async def test_get_app_transaction_info_app_transaction_does_not_exist(self):
693+
client = self.get_client_with_body_from_file('tests/resources/models/appTransactionDoesNotExistError.json',
694+
'GET',
695+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/nonexistent_id',
696+
{},
697+
None,
698+
404)
699+
try:
700+
await client.get_app_transaction_info('nonexistent_id')
701+
except APIException as e:
702+
self.assertEqual(404, e.http_status_code)
703+
self.assertEqual(4040019, e.raw_api_error)
704+
self.assertEqual(APIError.APP_TRANSACTION_DOES_NOT_EXIST_ERROR, e.api_error)
705+
self.assertEqual("No AppTransaction exists for the customer.", e.error_message)
706+
return
707+
708+
self.assertFalse(True)
709+
710+
async def test_get_app_transaction_info_transaction_id_not_found(self):
711+
client = self.get_client_with_body_from_file('tests/resources/models/transactionIdNotFoundError.json',
712+
'GET',
713+
'https://local-testing-base-url/inApps/v1/transactions/appTransactions/not_found_id',
714+
{},
715+
None,
716+
404)
717+
try:
718+
await client.get_app_transaction_info('not_found_id')
719+
except APIException as e:
720+
self.assertEqual(404, e.http_status_code)
721+
self.assertEqual(4040010, e.raw_api_error)
722+
self.assertEqual(APIError.TRANSACTION_ID_NOT_FOUND, e.api_error)
723+
self.assertEqual("Transaction id not found.", e.error_message)
724+
return
725+
726+
self.assertFalse(True)
660727

661728
def get_signing_key(self):
662729
return read_data_from_binary_file('tests/resources/certs/testSigningKey.p8')

0 commit comments

Comments
 (0)