1"""Example usage of the pyUSPTO module for PTAB Appeals API.
2
3This example demonstrates how to use the PTABAppealsClient to interact with the USPTO PTAB
4(Patent Trial and Appeal Board) Appeals API. It shows how to search for ex parte appeal
5decisions using various search criteria.
6
7PTAB Appeals include ex parte appeals from patent application examinations to the Board.
8"""
9
10import os
11
12from pyUSPTO import PTABAppealsClient
13from pyUSPTO.config import USPTOConfig
14
15# --- Initialization ---
16# Initialize the client with direct API key
17print("Initialize with direct API key")
18api_key = os.environ.get("USPTO_API_KEY", "YOUR_API_KEY_HERE")
19if api_key == "YOUR_API_KEY_HERE":
20 raise ValueError(
21 "WARNING: API key is not set. Please replace 'YOUR_API_KEY_HERE' or set USPTO_API_KEY environment variable."
22 )
23config = USPTOConfig(api_key=api_key)
24client = PTABAppealsClient(config=config)
25
26
27print("\nBeginning PTAB Appeals API requests with configured client:")
28# =============================================================================
29# 1. Search Appeal Decisions by Technology Center
30# =============================================================================
31
32print("\n" + "=" * 80)
33print("1. Searching for appeal decisions by technology center")
34print("=" * 80)
35
36try:
37 # Search for decisions from Technology Center 3600 (Business Methods/Software)
38 response = client.search_decisions(
39 technology_center_number_q="3600",
40 decision_date_from_q="2023-01-01",
41 decision_date_to_q="2023-12-31",
42 limit=5,
43 )
44
45 print(f"\nFound {response.count} appeal decisions from TC 3600 in 2023")
46 print(f"Displaying first {len(response.patent_appeal_data_bag)} results:")
47
48 for decision in response.patent_appeal_data_bag:
49 print(f"\n Appeal Number: {decision.appeal_number}")
50
51 if decision.appeal_meta_data:
52 meta = decision.appeal_meta_data
53 print(f" Application Type: {meta.application_type_category}")
54 print(f" Filing Date: {meta.appeal_filing_date}")
55
56 if decision.appellant_data:
57 appellant = decision.appellant_data
58 print(f" Application Number: {appellant.application_number_text}")
59 print(f" Technology Center: {appellant.technology_center_number}")
60
61 if appellant.inventor_name:
62 print(f" Inventor: {appellant.inventor_name}")
63
64 if decision.decision_data:
65 dec = decision.decision_data
66 print(f" Decision Type: {dec.decision_type_category}")
67 print(f" Decision Date: {dec.decision_issue_date}")
68
69except Exception as e:
70 print(f"Error searching appeal decisions: {e}")
71
72# =============================================================================
73# 2. Search by Decision Type
74# =============================================================================
75
76print("\n" + "=" * 80)
77print("2. Searching for 'Affirmed' decisions")
78print("=" * 80)
79
80try:
81 # Search for decisions where the examiner was affirmed
82 response = client.search_decisions(
83 decision_type_category_q="Decision",
84 decision_date_from_q="2024-01-01",
85 limit=5,
86 )
87
88 print(f"\nFound {response.count} 'Decision's since 2024")
89 print(f"Displaying first {len(response.patent_appeal_data_bag)} results:")
90
91 for decision in response.patent_appeal_data_bag:
92 print(f"\n Appeal Number: {decision.appeal_number}")
93
94 if decision.appellant_data:
95 print(f" Application: {decision.appellant_data.application_number_text}")
96 print(f" Inventor: {decision.appellant_data.inventor_name or 'N/A'}")
97
98 if decision.decision_data:
99 print(f" Decision: {decision.decision_data.decision_type_category}")
100 print(f" Outcome: {decision.decision_data.appeal_outcome_category}")
101 print(f" Date: {decision.decision_data.decision_issue_date}")
102
103except Exception as e:
104 print(f"Error searching by decision type: {e}")
105
106# =============================================================================
107# 3. Search by Application Number
108# =============================================================================
109
110print("\n" + "=" * 80)
111print("3. Searching for decisions by application number pattern")
112print("=" * 80)
113
114try:
115 # Search for decisions related to applications starting with "15"
116 response = client.search_decisions(
117 application_number_text_q="15*",
118 decision_date_from_q="2023-01-01",
119 limit=3,
120 )
121
122 print(f"\nFound {response.count} decisions for applications starting with '15/'")
123 print(f"Displaying first {len(response.patent_appeal_data_bag)} results:")
124
125 for decision in response.patent_appeal_data_bag:
126 print(f"\n Appeal Number: {decision.appeal_number}")
127
128 if decision.appellant_data:
129 print(f" Application: {decision.appellant_data.application_number_text}")
130 print(f" TC Number: {decision.appellant_data.technology_center_number}")
131
132 if decision.document_data:
133 doc = decision.document_data
134 print(f" Document Name: {doc.document_name}")
135 if doc.file_download_uri:
136 print(f" Download URL: {doc.file_download_uri}")
137
138except Exception as e:
139 print(f"Error searching by application number: {e}")
140
141# =============================================================================
142# 4. Pagination Example
143# =============================================================================
144
145print("\n" + "=" * 80)
146print("4. Paginating through appeal decisions")
147print("=" * 80)
148
149try:
150 print("\nIterating through first 10 appeal decisions from 2024...")
151 count = 0
152 for decision in client.paginate_decisions(
153 decision_date_from_q="2024-01-01",
154 limit=5, # Fetch 5 per page
155 ):
156 count += 1
157 decision_type = (
158 decision.decision_data.decision_type_category
159 if decision.decision_data
160 else "N/A"
161 )
162 print(f"{count}. {decision.appeal_number} - {decision_type}")
163
164 if count >= 10: # Stop after 10 results for this example
165 break
166
167 print(f"\nDisplayed {count} decisions using pagination")
168
169except Exception as e:
170 print(f"Error paginating decisions: {e}")
171
172# =============================================================================
173# 5. Advanced Search with Multiple Criteria
174# =============================================================================
175
176print("\n" + "=" * 80)
177print("5. Advanced search with multiple criteria")
178print("=" * 80)
179
180try:
181 # Search with multiple convenience parameters
182 response = client.search_decisions(
183 technology_center_number_q="2100", # Electronics
184 decision_type_category_q="Decision",
185 decision_date_from_q="2023-01-01",
186 decision_date_to_q="2023-12-31",
187 sort="decisionData.decisionIssueDate desc",
188 limit=3,
189 )
190
191 print(f"\nFound {response.count} Decisions from TC 2100 (Electronics) in 2023")
192 print(f"Displaying first {len(response.patent_appeal_data_bag)} results:")
193
194 for decision in response.patent_appeal_data_bag:
195 print(f"\n Appeal Number: {decision.appeal_number}")
196
197 if decision.appellant_data:
198 print(f" Application: {decision.appellant_data.application_number_text}")
199
200 if decision.decision_data:
201 print(f" Decision: {decision.decision_data.decision_type_category}")
202 print(f" Date: {decision.decision_data.decision_issue_date}")
203
204except Exception as e:
205 print(f"Error with advanced search: {e}")
206
207# =============================================================================
208# 6. Direct Query String Example
209# =============================================================================
210
211print("\n" + "=" * 80)
212print("6. Using direct query string for complex searches")
213print("=" * 80)
214
215try:
216 # Use a direct query string for more complex searches
217 response = client.search_decisions(
218 query="appellantData.technologyCenterNumber:3600 AND decisionData.appealOutcomeCategory:(Affirmed OR Reversed)",
219 limit=10,
220 )
221
222 print(f"\nFound {response.count} Affirmed/Reversed decisions from TC 3600")
223 print(f"Displaying first {len(response.patent_appeal_data_bag)} results:")
224
225 for decision in response.patent_appeal_data_bag:
226 print(f"\n Appeal Number: {decision.appeal_number}")
227 print(f" >App. Number: {decision.appellant_data.application_number_text}") # type: ignore
228 if decision.decision_data:
229 print(f" >Decision: {decision.decision_data.decision_type_category}")
230 print(f" >Outcome: {decision.decision_data.appeal_outcome_category}")
231
232except Exception as e:
233 print(f"Error with direct query: {e}")
234
235# =============================================================================
236# 7. Error Handling Example
237# =============================================================================
238
239print("\n" + "=" * 80)
240print("7. Error handling demonstration")
241print("=" * 80)
242
243try:
244 # Attempt a search that might return no results
245 print("\nAttempting search with unlikely parameters...")
246 response = client.search_decisions(
247 appeal_number_q="INVALID-APPEAL-NUMBER",
248 limit=1,
249 )
250
251 if response.count == 0:
252 print("No results found for the given search criteria")
253 else:
254 print(f"Found {response.count} results")
255
256except Exception as e:
257 print(f"Expected error occurred: {type(e).__name__}: {e}")
258
259print("\n" + "=" * 80)
260print("PTAB Appeals API example completed successfully!")
261print("=" * 80)