1pub mod billing;
2pub mod bulk;
3pub mod chains;
4pub mod endpoint_metrics;
5pub mod endpoint_rate_limits;
6pub mod endpoint_security;
7pub mod endpoint_urls;
8pub mod endpoints;
9pub mod logs;
10pub mod tags;
11pub mod teams;
12pub mod usage;
13
14pub use billing::{
15 Invoice, InvoiceLine, ListInvoicesData, ListInvoicesResponse, ListPaymentsData,
16 ListPaymentsResponse, Payment,
17};
18pub use bulk::{
19 BulkAddTagData, BulkAddTagRequest, BulkAddTagResponse, BulkOperationResult, BulkRemoveTagData,
20 BulkRemoveTagRequest, BulkRemoveTagResponse, BulkTag, BulkUpdateEndpointStatusData,
21 BulkUpdateEndpointStatusRequest, BulkUpdateEndpointStatusResponse,
22};
23pub use chains::{Chain, ChainNetwork, ListChainsResponse};
24pub use endpoint_metrics::{
25 EndpointMetric, GetAccountMetricsRequest, GetAccountMetricsResponse, GetEndpointMetricsRequest,
26 GetEndpointMetricsResponse,
27};
28pub use endpoint_rate_limits::{
29 CreateMethodRateLimitRequest, CreateMethodRateLimitResponse, GetMethodRateLimitsData,
30 GetMethodRateLimitsResponse, GetRateLimitsData, GetRateLimitsResponse, MethodRateLimiter,
31 RateLimitEntry, RateLimitSettings, UpdateMethodRateLimitRequest, UpdateMethodRateLimitResponse,
32 UpdateRateLimitsRequest,
33};
34pub use endpoint_security::{
35 CreateDomainMaskRequest, CreateIpRequest, CreateJwtRequest,
36 CreateOrUpdateIpCustomHeaderRequest, CreateOrUpdateIpCustomHeaderResponse,
37 CreateReferrerRequest, CreateRequestFilterData, CreateRequestFilterRequest,
38 CreateRequestFilterResponse, DeleteBoolResponse, GetSecurityOptionsResponse,
39 IpCustomHeaderData, SecurityOption, SecurityOptionsUpdate, UpdateRequestFilterRequest,
40 UpdateSecurityOptionsRequest, UpdateSecurityOptionsResponse,
41};
42pub use endpoint_urls::{EndpointUrl, GetEndpointUrlsData, GetEndpointUrlsResponse};
43pub use endpoints::{
44 CreateEndpointRequest, CreateEndpointResponse, CreateTagRequest, Endpoint, EndpointDomainMask,
45 EndpointIp, EndpointIpCustomHeaderOption, EndpointJwt, EndpointRateLimits, EndpointReferrer,
46 EndpointRequestFilter, EndpointSecurity, EndpointSecurityOptions, EndpointTag, EndpointToken,
47 GetEndpointSecurityResponse, GetEndpointsRequest, GetEndpointsResponse, Pagination,
48 ShowEndpointResponse, SingleEndpoint, UpdateEndpointRequest, UpdateEndpointStatusRequest,
49 UpdateEndpointStatusResponse,
50};
51pub use logs::{
52 EndpointLog, GetEndpointLogsRequest, GetEndpointLogsResponse, GetLogDetailsResponse, LogDetails,
53};
54pub use tags::{
55 AccountTag, DeleteAccountTagData, DeleteAccountTagResponse, ListTagsData, ListTagsResponse,
56 RenameTagRequest, RenameTagResponse,
57};
58pub use teams::{
59 CreateTeamData, CreateTeamRequest, CreateTeamResponse, DeleteTeamData, DeleteTeamResponse,
60 GetTeamResponse, InviteTeamMemberRequest, InviteTeamMemberResponse, ListTeamEndpointsResponse,
61 ListTeamsResponse, RemoveTeamMemberRequest, RemoveTeamMemberResponse, ResendTeamInviteResponse,
62 TeamDetail, TeamEndpoint, TeamMessageData, TeamSummary, TeamUser, UpdateTeamEndpointsData,
63 UpdateTeamEndpointsRequest, UpdateTeamEndpointsResponse,
64};
65
66pub use usage::{
67 ChainUsage, EndpointUsage, GetUsageByChainResponse, GetUsageByEndpointResponse,
68 GetUsageByMethodResponse, GetUsageByTagResponse, GetUsageRequest, GetUsageResponse,
69 MethodUsage, TagUsage, UsageByChainData, UsageByEndpointData, UsageByMethodData,
70 UsageByTagData, UsageData,
71};
72
73use crate::{config::AdminConfig, errors::SdkError, SdkConfig};
74
75const ADMIN_BASE_URL: &str = "https://api.quicknode.com/v0/";
76
77pub(crate) struct ResolvedAdminConfig {
78 pub(crate) base_url: reqwest::Url,
79}
80
81impl ResolvedAdminConfig {
82 pub(crate) fn from_config(config: Option<&AdminConfig>) -> Result<Self, SdkError> {
83 let url_str = config
84 .and_then(|a| a.base_url.as_deref())
85 .unwrap_or(ADMIN_BASE_URL);
86 let mut base_url = reqwest::Url::parse(url_str)?;
87 if !base_url.path().ends_with('/') {
88 base_url.set_path(&format!("{}/", base_url.path()));
89 }
90 Ok(Self { base_url })
91 }
92}
93
94#[derive(Debug, Clone)]
97pub struct AdminApiClient {
98 config: SdkConfig,
99}
100
101impl AdminApiClient {
102 pub fn new(config: SdkConfig) -> Self {
103 Self { config }
104 }
105
106 pub async fn get_endpoints(
112 &self,
113 params: &GetEndpointsRequest,
114 ) -> Result<GetEndpointsResponse, SdkError> {
115 let url = self.config.admin().base_url.join("endpoints")?;
116 let query = endpoints_query(params);
120 let resp = self
121 .config
122 .http_client()
123 .get(url)
124 .query(&query)
125 .send()
126 .await
127 .map_err(SdkError::Http)?;
128
129 let status = resp.status();
130 let body = resp.text().await.map_err(SdkError::Http)?;
131
132 if !status.is_success() {
133 return Err(SdkError::Api { status, body });
134 }
135 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
136 }
137
138 pub async fn create_endpoint(
143 &self,
144 params: &CreateEndpointRequest,
145 ) -> Result<CreateEndpointResponse, SdkError> {
146 let url = self.config.admin().base_url.join("endpoints")?;
147 let resp = self
148 .config
149 .http_client()
150 .post(url)
151 .json(params)
152 .send()
153 .await
154 .map_err(SdkError::Http)?;
155
156 let status = resp.status();
157 let body = resp.text().await.map_err(SdkError::Http)?;
158
159 if !status.is_success() {
160 return Err(SdkError::Api { status, body });
161 }
162 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
163 }
164
165 pub async fn show_endpoint(&self, id: &str) -> Result<ShowEndpointResponse, SdkError> {
167 let url = self
168 .config
169 .admin()
170 .base_url
171 .join(&format!("endpoints/{}", id))?;
172 let resp = self
173 .config
174 .http_client()
175 .get(url)
176 .send()
177 .await
178 .map_err(SdkError::Http)?;
179
180 let status = resp.status();
181 let body = resp.text().await.map_err(SdkError::Http)?;
182
183 if !status.is_success() {
184 return Err(SdkError::Api { status, body });
185 }
186 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
187 }
188
189 pub async fn update_endpoint(
192 &self,
193 id: &str,
194 params: &UpdateEndpointRequest,
195 ) -> Result<(), SdkError> {
196 let url = self
197 .config
198 .admin()
199 .base_url
200 .join(&format!("endpoints/{}", id))?;
201 let resp = self
202 .config
203 .http_client()
204 .patch(url)
205 .json(params)
206 .send()
207 .await
208 .map_err(SdkError::Http)?;
209
210 let status = resp.status();
211 let body = resp.text().await.map_err(SdkError::Http)?;
212
213 if !status.is_success() {
214 return Err(SdkError::Api { status, body });
215 }
216 Ok(())
217 }
218
219 pub async fn archive_endpoint(&self, id: &str) -> Result<(), SdkError> {
222 let url = self
223 .config
224 .admin()
225 .base_url
226 .join(&format!("endpoints/{}", id))?;
227 let resp = self
228 .config
229 .http_client()
230 .delete(url)
231 .send()
232 .await
233 .map_err(SdkError::Http)?;
234
235 let status = resp.status();
236 let body = resp.text().await.map_err(SdkError::Http)?;
237
238 if !status.is_success() {
239 return Err(SdkError::Api { status, body });
240 }
241 Ok(())
242 }
243
244 pub async fn update_endpoint_status(
247 &self,
248 id: &str,
249 params: &UpdateEndpointStatusRequest,
250 ) -> Result<UpdateEndpointStatusResponse, SdkError> {
251 let url = self
252 .config
253 .admin()
254 .base_url
255 .join(&format!("endpoints/{}/status", id))?;
256 let resp = self
257 .config
258 .http_client()
259 .patch(url)
260 .json(params)
261 .send()
262 .await
263 .map_err(SdkError::Http)?;
264
265 let status = resp.status();
266 let body = resp.text().await.map_err(SdkError::Http)?;
267
268 if !status.is_success() {
269 return Err(SdkError::Api { status, body });
270 }
271 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
272 }
273
274 pub async fn create_tag(&self, id: &str, params: &CreateTagRequest) -> Result<(), SdkError> {
277 let url = self
278 .config
279 .admin()
280 .base_url
281 .join(&format!("endpoints/{}/tags", id))?;
282 let resp = self
283 .config
284 .http_client()
285 .post(url)
286 .json(params)
287 .send()
288 .await
289 .map_err(SdkError::Http)?;
290
291 let status = resp.status();
292 let body = resp.text().await.map_err(SdkError::Http)?;
293
294 if !status.is_success() {
295 return Err(SdkError::Api { status, body });
296 }
297 Ok(())
298 }
299
300 pub async fn delete_tag(&self, id: &str, tag_id: &str) -> Result<(), SdkError> {
302 let url = self
303 .config
304 .admin()
305 .base_url
306 .join(&format!("endpoints/{}/tags/{}", id, tag_id))?;
307 let resp = self
308 .config
309 .http_client()
310 .delete(url)
311 .send()
312 .await
313 .map_err(SdkError::Http)?;
314
315 let status = resp.status();
316 let body = resp.text().await.map_err(SdkError::Http)?;
317
318 if !status.is_success() {
319 return Err(SdkError::Api { status, body });
320 }
321 Ok(())
322 }
323
324 pub async fn list_teams(&self) -> Result<ListTeamsResponse, SdkError> {
327 let url = self.config.admin().base_url.join("teams")?;
328 let resp = self
329 .config
330 .http_client()
331 .get(url)
332 .send()
333 .await
334 .map_err(SdkError::Http)?;
335
336 let status = resp.status();
337 let body = resp.text().await.map_err(SdkError::Http)?;
338
339 if !status.is_success() {
340 return Err(SdkError::Api { status, body });
341 }
342 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
343 }
344
345 pub async fn create_team(
348 &self,
349 params: &CreateTeamRequest,
350 ) -> Result<CreateTeamResponse, SdkError> {
351 let url = self.config.admin().base_url.join("teams")?;
352 let resp = self
353 .config
354 .http_client()
355 .post(url)
356 .json(params)
357 .send()
358 .await
359 .map_err(SdkError::Http)?;
360
361 let status = resp.status();
362 let body = resp.text().await.map_err(SdkError::Http)?;
363
364 if !status.is_success() {
365 return Err(SdkError::Api { status, body });
366 }
367 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
368 }
369
370 pub async fn get_team(&self, id: i64) -> Result<GetTeamResponse, SdkError> {
373 let url = self
374 .config
375 .admin()
376 .base_url
377 .join(&format!("teams/{}", id))?;
378 let resp = self
379 .config
380 .http_client()
381 .get(url)
382 .send()
383 .await
384 .map_err(SdkError::Http)?;
385
386 let status = resp.status();
387 let body = resp.text().await.map_err(SdkError::Http)?;
388
389 if !status.is_success() {
390 return Err(SdkError::Api { status, body });
391 }
392 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
393 }
394
395 pub async fn delete_team(&self, id: i64) -> Result<DeleteTeamResponse, SdkError> {
398 let url = self
399 .config
400 .admin()
401 .base_url
402 .join(&format!("teams/{}", id))?;
403 let resp = self
404 .config
405 .http_client()
406 .delete(url)
407 .send()
408 .await
409 .map_err(SdkError::Http)?;
410
411 let status = resp.status();
412 let body = resp.text().await.map_err(SdkError::Http)?;
413
414 if !status.is_success() {
415 return Err(SdkError::Api { status, body });
416 }
417 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
418 }
419
420 pub async fn list_team_endpoints(
423 &self,
424 id: i64,
425 ) -> Result<ListTeamEndpointsResponse, SdkError> {
426 let url = self
427 .config
428 .admin()
429 .base_url
430 .join(&format!("teams/{}/endpoints", id))?;
431 let resp = self
432 .config
433 .http_client()
434 .get(url)
435 .send()
436 .await
437 .map_err(SdkError::Http)?;
438
439 let status = resp.status();
440 let body = resp.text().await.map_err(SdkError::Http)?;
441
442 if !status.is_success() {
443 return Err(SdkError::Api { status, body });
444 }
445 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
446 }
447
448 pub async fn update_team_endpoints(
452 &self,
453 id: i64,
454 params: &UpdateTeamEndpointsRequest,
455 ) -> Result<UpdateTeamEndpointsResponse, SdkError> {
456 let url = self
457 .config
458 .admin()
459 .base_url
460 .join(&format!("teams/{}/endpoints", id))?;
461 let resp = self
462 .config
463 .http_client()
464 .patch(url)
465 .json(params)
466 .send()
467 .await
468 .map_err(SdkError::Http)?;
469
470 let status = resp.status();
471 let body = resp.text().await.map_err(SdkError::Http)?;
472
473 if !status.is_success() {
474 return Err(SdkError::Api { status, body });
475 }
476 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
477 }
478
479 pub async fn invite_team_member(
483 &self,
484 id: i64,
485 params: &InviteTeamMemberRequest,
486 ) -> Result<InviteTeamMemberResponse, SdkError> {
487 let url = self
488 .config
489 .admin()
490 .base_url
491 .join(&format!("teams/{}/members", id))?;
492 let resp = self
493 .config
494 .http_client()
495 .post(url)
496 .json(params)
497 .send()
498 .await
499 .map_err(SdkError::Http)?;
500
501 let status = resp.status();
502 let body = resp.text().await.map_err(SdkError::Http)?;
503
504 if !status.is_success() {
505 return Err(SdkError::Api { status, body });
506 }
507 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
508 }
509
510 pub async fn remove_team_member(
512 &self,
513 id: i64,
514 user_id: i64,
515 params: &RemoveTeamMemberRequest,
516 ) -> Result<RemoveTeamMemberResponse, SdkError> {
517 let url = self
518 .config
519 .admin()
520 .base_url
521 .join(&format!("teams/{}/members/{}", id, user_id))?;
522 let resp = self
523 .config
524 .http_client()
525 .delete(url)
526 .json(params)
527 .send()
528 .await
529 .map_err(SdkError::Http)?;
530
531 let status = resp.status();
532 let body = resp.text().await.map_err(SdkError::Http)?;
533
534 if !status.is_success() {
535 return Err(SdkError::Api { status, body });
536 }
537 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
538 }
539
540 pub async fn resend_team_invite(
543 &self,
544 id: i64,
545 user_id: i64,
546 ) -> Result<ResendTeamInviteResponse, SdkError> {
547 let url = self
548 .config
549 .admin()
550 .base_url
551 .join(&format!("teams/{}/members/{}/resend_invite", id, user_id))?;
552 let resp = self
553 .config
554 .http_client()
555 .post(url)
556 .send()
557 .await
558 .map_err(SdkError::Http)?;
559
560 let status = resp.status();
561 let body = resp.text().await.map_err(SdkError::Http)?;
562
563 if !status.is_success() {
564 return Err(SdkError::Api { status, body });
565 }
566 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
567 }
568
569 pub async fn get_usage(&self, params: &GetUsageRequest) -> Result<GetUsageResponse, SdkError> {
573 let url = self.config.admin().base_url.join("usage/rpc")?;
574 let resp = self
575 .config
576 .http_client()
577 .get(url)
578 .query(params)
579 .send()
580 .await
581 .map_err(SdkError::Http)?;
582
583 let status = resp.status();
584 let body = resp.text().await.map_err(SdkError::Http)?;
585
586 if !status.is_success() {
587 return Err(SdkError::Api { status, body });
588 }
589 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
590 }
591
592 pub async fn get_usage_by_endpoint(
596 &self,
597 params: &GetUsageRequest,
598 ) -> Result<GetUsageByEndpointResponse, SdkError> {
599 let url = self.config.admin().base_url.join("usage/rpc/by-endpoint")?;
600 let resp = self
601 .config
602 .http_client()
603 .get(url)
604 .query(params)
605 .send()
606 .await
607 .map_err(SdkError::Http)?;
608
609 let status = resp.status();
610 let body = resp.text().await.map_err(SdkError::Http)?;
611
612 if !status.is_success() {
613 return Err(SdkError::Api { status, body });
614 }
615 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
616 }
617
618 pub async fn get_usage_by_method(
622 &self,
623 params: &GetUsageRequest,
624 ) -> Result<GetUsageByMethodResponse, SdkError> {
625 let url = self.config.admin().base_url.join("usage/rpc/by-method")?;
626 let resp = self
627 .config
628 .http_client()
629 .get(url)
630 .query(params)
631 .send()
632 .await
633 .map_err(SdkError::Http)?;
634
635 let status = resp.status();
636 let body = resp.text().await.map_err(SdkError::Http)?;
637
638 if !status.is_success() {
639 return Err(SdkError::Api { status, body });
640 }
641 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
642 }
643
644 pub async fn get_usage_by_chain(
647 &self,
648 params: &GetUsageRequest,
649 ) -> Result<GetUsageByChainResponse, SdkError> {
650 let url = self.config.admin().base_url.join("usage/rpc/by-chain")?;
651 let resp = self
652 .config
653 .http_client()
654 .get(url)
655 .query(params)
656 .send()
657 .await
658 .map_err(SdkError::Http)?;
659
660 let status = resp.status();
661 let body = resp.text().await.map_err(SdkError::Http)?;
662
663 if !status.is_success() {
664 return Err(SdkError::Api { status, body });
665 }
666 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
667 }
668
669 pub async fn get_endpoint_logs(
674 &self,
675 id: &str,
676 params: &GetEndpointLogsRequest,
677 ) -> Result<GetEndpointLogsResponse, SdkError> {
678 let url = self
679 .config
680 .admin()
681 .base_url
682 .join(&format!("endpoints/{}/logs", id))?;
683 let resp = self
684 .config
685 .http_client()
686 .get(url)
687 .query(params)
688 .send()
689 .await
690 .map_err(SdkError::Http)?;
691
692 let status = resp.status();
693 let body = resp.text().await.map_err(SdkError::Http)?;
694
695 if !status.is_success() {
696 return Err(SdkError::Api { status, body });
697 }
698 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
699 }
700
701 pub async fn get_log_details(
705 &self,
706 id: &str,
707 request_id: &str,
708 ) -> Result<GetLogDetailsResponse, SdkError> {
709 let url = self
710 .config
711 .admin()
712 .base_url
713 .join(&format!("endpoints/{}/log_details", id))?;
714 let resp = self
715 .config
716 .http_client()
717 .get(url)
718 .query(&[("request_id", request_id)])
719 .send()
720 .await
721 .map_err(SdkError::Http)?;
722
723 let status = resp.status();
724 let body = resp.text().await.map_err(SdkError::Http)?;
725
726 if !status.is_success() {
727 return Err(SdkError::Api { status, body });
728 }
729 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
730 }
731
732 pub async fn get_security_options(
735 &self,
736 id: &str,
737 ) -> Result<GetSecurityOptionsResponse, SdkError> {
738 let url = self
739 .config
740 .admin()
741 .base_url
742 .join(&format!("endpoints/{}/security_options", id))?;
743 let resp = self
744 .config
745 .http_client()
746 .get(url)
747 .send()
748 .await
749 .map_err(SdkError::Http)?;
750
751 let status = resp.status();
752 let body = resp.text().await.map_err(SdkError::Http)?;
753
754 if !status.is_success() {
755 return Err(SdkError::Api { status, body });
756 }
757 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
758 }
759
760 pub async fn update_security_options(
765 &self,
766 id: &str,
767 params: &UpdateSecurityOptionsRequest,
768 ) -> Result<UpdateSecurityOptionsResponse, SdkError> {
769 let url = self
770 .config
771 .admin()
772 .base_url
773 .join(&format!("endpoints/{}/security_options", id))?;
774 let resp = self
775 .config
776 .http_client()
777 .patch(url)
778 .json(params)
779 .send()
780 .await
781 .map_err(SdkError::Http)?;
782
783 let status = resp.status();
784 let body = resp.text().await.map_err(SdkError::Http)?;
785
786 if !status.is_success() {
787 return Err(SdkError::Api { status, body });
788 }
789 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
790 }
791
792 pub async fn create_token(&self, id: &str) -> Result<(), SdkError> {
794 let url = self
795 .config
796 .admin()
797 .base_url
798 .join(&format!("endpoints/{}/security/tokens", id))?;
799 let resp = self
800 .config
801 .http_client()
802 .post(url)
803 .send()
804 .await
805 .map_err(SdkError::Http)?;
806
807 let status = resp.status();
808 let body = resp.text().await.map_err(SdkError::Http)?;
809
810 if !status.is_success() {
811 return Err(SdkError::Api { status, body });
812 }
813 Ok(())
814 }
815
816 pub async fn delete_token(
818 &self,
819 id: &str,
820 token_id: &str,
821 ) -> Result<DeleteBoolResponse, SdkError> {
822 let url = self
823 .config
824 .admin()
825 .base_url
826 .join(&format!("endpoints/{}/security/tokens/{}", id, token_id))?;
827 let resp = self
828 .config
829 .http_client()
830 .delete(url)
831 .send()
832 .await
833 .map_err(SdkError::Http)?;
834
835 let status = resp.status();
836 let body = resp.text().await.map_err(SdkError::Http)?;
837
838 if !status.is_success() {
839 return Err(SdkError::Api { status, body });
840 }
841 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
842 }
843
844 pub async fn create_referrer(
847 &self,
848 id: &str,
849 params: &CreateReferrerRequest,
850 ) -> Result<(), SdkError> {
851 let url = self
852 .config
853 .admin()
854 .base_url
855 .join(&format!("endpoints/{}/security/referrers", id))?;
856 let resp = self
857 .config
858 .http_client()
859 .post(url)
860 .json(params)
861 .send()
862 .await
863 .map_err(SdkError::Http)?;
864
865 let status = resp.status();
866 let body = resp.text().await.map_err(SdkError::Http)?;
867
868 if !status.is_success() {
869 return Err(SdkError::Api { status, body });
870 }
871 Ok(())
872 }
873
874 pub async fn delete_referrer(
876 &self,
877 id: &str,
878 referrer_id: &str,
879 ) -> Result<DeleteBoolResponse, SdkError> {
880 let url = self.config.admin().base_url.join(&format!(
881 "endpoints/{}/security/referrers/{}",
882 id, referrer_id
883 ))?;
884 let resp = self
885 .config
886 .http_client()
887 .delete(url)
888 .send()
889 .await
890 .map_err(SdkError::Http)?;
891
892 let status = resp.status();
893 let body = resp.text().await.map_err(SdkError::Http)?;
894
895 if !status.is_success() {
896 return Err(SdkError::Api { status, body });
897 }
898 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
899 }
900
901 pub async fn create_ip(&self, id: &str, params: &CreateIpRequest) -> Result<(), SdkError> {
903 let url = self
904 .config
905 .admin()
906 .base_url
907 .join(&format!("endpoints/{}/security/ips", id))?;
908 let resp = self
909 .config
910 .http_client()
911 .post(url)
912 .json(params)
913 .send()
914 .await
915 .map_err(SdkError::Http)?;
916
917 let status = resp.status();
918 let body = resp.text().await.map_err(SdkError::Http)?;
919
920 if !status.is_success() {
921 return Err(SdkError::Api { status, body });
922 }
923 Ok(())
924 }
925
926 pub async fn delete_ip(&self, id: &str, ip_id: &str) -> Result<DeleteBoolResponse, SdkError> {
928 let url = self
929 .config
930 .admin()
931 .base_url
932 .join(&format!("endpoints/{}/security/ips/{}", id, ip_id))?;
933 let resp = self
934 .config
935 .http_client()
936 .delete(url)
937 .send()
938 .await
939 .map_err(SdkError::Http)?;
940
941 let status = resp.status();
942 let body = resp.text().await.map_err(SdkError::Http)?;
943
944 if !status.is_success() {
945 return Err(SdkError::Api { status, body });
946 }
947 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
948 }
949
950 pub async fn create_domain_mask(
954 &self,
955 id: &str,
956 params: &CreateDomainMaskRequest,
957 ) -> Result<(), SdkError> {
958 let url = self
959 .config
960 .admin()
961 .base_url
962 .join(&format!("endpoints/{}/security/domain_masks", id))?;
963 let resp = self
964 .config
965 .http_client()
966 .post(url)
967 .json(params)
968 .send()
969 .await
970 .map_err(SdkError::Http)?;
971
972 let status = resp.status();
973 let body = resp.text().await.map_err(SdkError::Http)?;
974
975 if !status.is_success() {
976 return Err(SdkError::Api { status, body });
977 }
978 Ok(())
979 }
980
981 pub async fn delete_domain_mask(
983 &self,
984 id: &str,
985 domain_mask_id: &str,
986 ) -> Result<DeleteBoolResponse, SdkError> {
987 let url = self.config.admin().base_url.join(&format!(
988 "endpoints/{}/security/domain_masks/{}",
989 id, domain_mask_id
990 ))?;
991 let resp = self
992 .config
993 .http_client()
994 .delete(url)
995 .send()
996 .await
997 .map_err(SdkError::Http)?;
998
999 let status = resp.status();
1000 let body = resp.text().await.map_err(SdkError::Http)?;
1001
1002 if !status.is_success() {
1003 return Err(SdkError::Api { status, body });
1004 }
1005 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1006 }
1007
1008 pub async fn create_jwt(&self, id: &str, params: &CreateJwtRequest) -> Result<(), SdkError> {
1011 let url = self
1012 .config
1013 .admin()
1014 .base_url
1015 .join(&format!("endpoints/{}/security/jwts", id))?;
1016 let resp = self
1017 .config
1018 .http_client()
1019 .post(url)
1020 .json(params)
1021 .send()
1022 .await
1023 .map_err(SdkError::Http)?;
1024
1025 let status = resp.status();
1026 let body = resp.text().await.map_err(SdkError::Http)?;
1027
1028 if !status.is_success() {
1029 return Err(SdkError::Api { status, body });
1030 }
1031 Ok(())
1032 }
1033
1034 pub async fn delete_jwt(&self, id: &str, jwt_id: &str) -> Result<(), SdkError> {
1037 let url = self
1038 .config
1039 .admin()
1040 .base_url
1041 .join(&format!("endpoints/{}/security/jwts/{}", id, jwt_id))?;
1042 let resp = self
1043 .config
1044 .http_client()
1045 .delete(url)
1046 .send()
1047 .await
1048 .map_err(SdkError::Http)?;
1049
1050 let status = resp.status();
1051 let body = resp.text().await.map_err(SdkError::Http)?;
1052
1053 if !status.is_success() {
1054 return Err(SdkError::Api { status, body });
1055 }
1056 Ok(())
1057 }
1058
1059 pub async fn create_request_filter(
1063 &self,
1064 id: &str,
1065 params: &CreateRequestFilterRequest,
1066 ) -> Result<CreateRequestFilterResponse, SdkError> {
1067 let url = self
1068 .config
1069 .admin()
1070 .base_url
1071 .join(&format!("endpoints/{}/security/request_filters", id))?;
1072 let resp = self
1073 .config
1074 .http_client()
1075 .post(url)
1076 .json(params)
1077 .send()
1078 .await
1079 .map_err(SdkError::Http)?;
1080
1081 let status = resp.status();
1082 let body = resp.text().await.map_err(SdkError::Http)?;
1083
1084 if !status.is_success() {
1085 return Err(SdkError::Api { status, body });
1086 }
1087 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1088 }
1089
1090 pub async fn update_request_filter(
1093 &self,
1094 id: &str,
1095 request_filter_id: &str,
1096 params: &UpdateRequestFilterRequest,
1097 ) -> Result<(), SdkError> {
1098 let url = self.config.admin().base_url.join(&format!(
1099 "endpoints/{}/security/request_filters/{}",
1100 id, request_filter_id
1101 ))?;
1102 let resp = self
1103 .config
1104 .http_client()
1105 .put(url)
1106 .json(params)
1107 .send()
1108 .await
1109 .map_err(SdkError::Http)?;
1110
1111 let status = resp.status();
1112 let body = resp.text().await.map_err(SdkError::Http)?;
1113
1114 if !status.is_success() {
1115 return Err(SdkError::Api { status, body });
1116 }
1117 Ok(())
1118 }
1119
1120 pub async fn delete_request_filter(
1123 &self,
1124 id: &str,
1125 request_filter_id: &str,
1126 ) -> Result<(), SdkError> {
1127 let url = self.config.admin().base_url.join(&format!(
1128 "endpoints/{}/security/request_filters/{}",
1129 id, request_filter_id
1130 ))?;
1131 let resp = self
1132 .config
1133 .http_client()
1134 .delete(url)
1135 .send()
1136 .await
1137 .map_err(SdkError::Http)?;
1138
1139 let status = resp.status();
1140 let body = resp.text().await.map_err(SdkError::Http)?;
1141
1142 if !status.is_success() {
1143 return Err(SdkError::Api { status, body });
1144 }
1145 Ok(())
1146 }
1147
1148 pub async fn enable_multichain(&self, id: &str) -> Result<(), SdkError> {
1151 let url = self
1152 .config
1153 .admin()
1154 .base_url
1155 .join(&format!("endpoints/{}/enable_multichain", id))?;
1156 let resp = self
1157 .config
1158 .http_client()
1159 .post(url)
1160 .send()
1161 .await
1162 .map_err(SdkError::Http)?;
1163
1164 let status = resp.status();
1165 let body = resp.text().await.map_err(SdkError::Http)?;
1166
1167 if !status.is_success() {
1168 return Err(SdkError::Api { status, body });
1169 }
1170 Ok(())
1171 }
1172
1173 pub async fn disable_multichain(&self, id: &str) -> Result<(), SdkError> {
1175 let url = self
1176 .config
1177 .admin()
1178 .base_url
1179 .join(&format!("endpoints/{}/disable_multichain", id))?;
1180 let resp = self
1181 .config
1182 .http_client()
1183 .post(url)
1184 .send()
1185 .await
1186 .map_err(SdkError::Http)?;
1187
1188 let status = resp.status();
1189 let body = resp.text().await.map_err(SdkError::Http)?;
1190
1191 if !status.is_success() {
1192 return Err(SdkError::Api { status, body });
1193 }
1194 Ok(())
1195 }
1196
1197 pub async fn create_or_update_ip_custom_header(
1202 &self,
1203 id: &str,
1204 params: &CreateOrUpdateIpCustomHeaderRequest,
1205 ) -> Result<CreateOrUpdateIpCustomHeaderResponse, SdkError> {
1206 let url = self
1207 .config
1208 .admin()
1209 .base_url
1210 .join(&format!("endpoints/{}/ip_custom_header", id))?;
1211 let resp = self
1212 .config
1213 .http_client()
1214 .patch(url)
1215 .json(params)
1216 .send()
1217 .await
1218 .map_err(SdkError::Http)?;
1219
1220 let status = resp.status();
1221 let body = resp.text().await.map_err(SdkError::Http)?;
1222
1223 if !status.is_success() {
1224 return Err(SdkError::Api { status, body });
1225 }
1226 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1227 }
1228
1229 pub async fn delete_ip_custom_header(&self, id: &str) -> Result<DeleteBoolResponse, SdkError> {
1231 let url = self
1232 .config
1233 .admin()
1234 .base_url
1235 .join(&format!("endpoints/{}/ip_custom_header", id))?;
1236 let resp = self
1237 .config
1238 .http_client()
1239 .delete(url)
1240 .send()
1241 .await
1242 .map_err(SdkError::Http)?;
1243
1244 let status = resp.status();
1245 let body = resp.text().await.map_err(SdkError::Http)?;
1246
1247 if !status.is_success() {
1248 return Err(SdkError::Api { status, body });
1249 }
1250 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1251 }
1252
1253 pub async fn get_method_rate_limits(
1256 &self,
1257 id: &str,
1258 ) -> Result<GetMethodRateLimitsResponse, SdkError> {
1259 let url = self
1260 .config
1261 .admin()
1262 .base_url
1263 .join(&format!("endpoints/{}/method-rate-limits", id))?;
1264 let resp = self
1265 .config
1266 .http_client()
1267 .get(url)
1268 .send()
1269 .await
1270 .map_err(SdkError::Http)?;
1271
1272 let status = resp.status();
1273 let body = resp.text().await.map_err(SdkError::Http)?;
1274
1275 if !status.is_success() {
1276 return Err(SdkError::Api { status, body });
1277 }
1278 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1279 }
1280
1281 pub async fn create_method_rate_limit(
1285 &self,
1286 id: &str,
1287 params: &CreateMethodRateLimitRequest,
1288 ) -> Result<CreateMethodRateLimitResponse, SdkError> {
1289 let url = self
1290 .config
1291 .admin()
1292 .base_url
1293 .join(&format!("endpoints/{}/method-rate-limits", id))?;
1294 let resp = self
1295 .config
1296 .http_client()
1297 .post(url)
1298 .json(params)
1299 .send()
1300 .await
1301 .map_err(SdkError::Http)?;
1302
1303 let status = resp.status();
1304 let body = resp.text().await.map_err(SdkError::Http)?;
1305
1306 if !status.is_success() {
1307 return Err(SdkError::Api { status, body });
1308 }
1309 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1310 }
1311
1312 pub async fn update_method_rate_limit(
1315 &self,
1316 id: &str,
1317 method_rate_limit_id: &str,
1318 params: &UpdateMethodRateLimitRequest,
1319 ) -> Result<UpdateMethodRateLimitResponse, SdkError> {
1320 let url = self.config.admin().base_url.join(&format!(
1321 "endpoints/{}/method-rate-limits/{}",
1322 id, method_rate_limit_id
1323 ))?;
1324 let resp = self
1325 .config
1326 .http_client()
1327 .patch(url)
1328 .json(params)
1329 .send()
1330 .await
1331 .map_err(SdkError::Http)?;
1332
1333 let status = resp.status();
1334 let body = resp.text().await.map_err(SdkError::Http)?;
1335
1336 if !status.is_success() {
1337 return Err(SdkError::Api { status, body });
1338 }
1339 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1340 }
1341
1342 pub async fn delete_method_rate_limit(
1344 &self,
1345 id: &str,
1346 method_rate_limit_id: &str,
1347 ) -> Result<(), SdkError> {
1348 let url = self.config.admin().base_url.join(&format!(
1349 "endpoints/{}/method-rate-limits/{}",
1350 id, method_rate_limit_id
1351 ))?;
1352 let resp = self
1353 .config
1354 .http_client()
1355 .delete(url)
1356 .send()
1357 .await
1358 .map_err(SdkError::Http)?;
1359
1360 let status = resp.status();
1361 let body = resp.text().await.map_err(SdkError::Http)?;
1362
1363 if !status.is_success() {
1364 return Err(SdkError::Api { status, body });
1365 }
1366 Ok(())
1367 }
1368
1369 pub async fn update_rate_limits(
1375 &self,
1376 id: &str,
1377 params: &UpdateRateLimitsRequest,
1378 ) -> Result<(), SdkError> {
1379 let url = self
1380 .config
1381 .admin()
1382 .base_url
1383 .join(&format!("endpoints/{}/rate-limits", id))?;
1384 let resp = self
1385 .config
1386 .http_client()
1387 .patch(url)
1388 .json(params)
1389 .send()
1390 .await
1391 .map_err(SdkError::Http)?;
1392
1393 let status = resp.status();
1394 let body = resp.text().await.map_err(SdkError::Http)?;
1395
1396 if !status.is_success() {
1397 return Err(SdkError::Api { status, body });
1398 }
1399 Ok(())
1400 }
1401
1402 pub async fn get_rate_limits(&self, id: &str) -> Result<GetRateLimitsResponse, SdkError> {
1407 let url = self
1408 .config
1409 .admin()
1410 .base_url
1411 .join(&format!("endpoints/{}/rate-limits", id))?;
1412 let resp = self
1413 .config
1414 .http_client()
1415 .get(url)
1416 .send()
1417 .await
1418 .map_err(SdkError::Http)?;
1419
1420 let status = resp.status();
1421 let body = resp.text().await.map_err(SdkError::Http)?;
1422
1423 if !status.is_success() {
1424 return Err(SdkError::Api { status, body });
1425 }
1426 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1427 }
1428
1429 pub async fn delete_rate_limit_override(
1433 &self,
1434 id: &str,
1435 override_id: &str,
1436 ) -> Result<(), SdkError> {
1437 let url = self
1438 .config
1439 .admin()
1440 .base_url
1441 .join(&format!("endpoints/{}/rate-limits/{}", id, override_id))?;
1442 let resp = self
1443 .config
1444 .http_client()
1445 .delete(url)
1446 .send()
1447 .await
1448 .map_err(SdkError::Http)?;
1449
1450 let status = resp.status();
1451 let body = resp.text().await.map_err(SdkError::Http)?;
1452
1453 if !status.is_success() {
1454 return Err(SdkError::Api { status, body });
1455 }
1456 Ok(())
1457 }
1458
1459 pub async fn get_endpoint_urls(&self, id: &str) -> Result<GetEndpointUrlsResponse, SdkError> {
1464 let url = self
1465 .config
1466 .admin()
1467 .base_url
1468 .join(&format!("endpoints/{}/urls", id))?;
1469 let resp = self
1470 .config
1471 .http_client()
1472 .get(url)
1473 .send()
1474 .await
1475 .map_err(SdkError::Http)?;
1476
1477 let status = resp.status();
1478 let body = resp.text().await.map_err(SdkError::Http)?;
1479
1480 if !status.is_success() {
1481 return Err(SdkError::Api { status, body });
1482 }
1483 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1484 }
1485
1486 pub async fn get_endpoint_metrics(
1490 &self,
1491 id: &str,
1492 params: &GetEndpointMetricsRequest,
1493 ) -> Result<GetEndpointMetricsResponse, SdkError> {
1494 let url = self
1495 .config
1496 .admin()
1497 .base_url
1498 .join(&format!("endpoints/{}/metrics", id))?;
1499 let resp = self
1500 .config
1501 .http_client()
1502 .get(url)
1503 .query(params)
1504 .send()
1505 .await
1506 .map_err(SdkError::Http)?;
1507
1508 let status = resp.status();
1509 let body = resp.text().await.map_err(SdkError::Http)?;
1510
1511 if !status.is_success() {
1512 return Err(SdkError::Api { status, body });
1513 }
1514 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1515 }
1516
1517 pub async fn get_account_metrics(
1521 &self,
1522 params: &GetAccountMetricsRequest,
1523 ) -> Result<GetAccountMetricsResponse, SdkError> {
1524 let url = self.config.admin().base_url.join("metrics")?;
1525 let resp = self
1526 .config
1527 .http_client()
1528 .get(url)
1529 .query(params)
1530 .send()
1531 .await
1532 .map_err(SdkError::Http)?;
1533
1534 let status = resp.status();
1535 let body = resp.text().await.map_err(SdkError::Http)?;
1536
1537 if !status.is_success() {
1538 return Err(SdkError::Api { status, body });
1539 }
1540 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1541 }
1542
1543 pub async fn list_chains(&self) -> Result<ListChainsResponse, SdkError> {
1546 let url = self.config.admin().base_url.join("chains")?;
1547 let resp = self
1548 .config
1549 .http_client()
1550 .get(url)
1551 .send()
1552 .await
1553 .map_err(SdkError::Http)?;
1554
1555 let status = resp.status();
1556 let body = resp.text().await.map_err(SdkError::Http)?;
1557
1558 if !status.is_success() {
1559 return Err(SdkError::Api { status, body });
1560 }
1561 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1562 }
1563
1564 pub async fn list_invoices(&self) -> Result<ListInvoicesResponse, SdkError> {
1568 let url = self.config.admin().base_url.join("billing/invoices")?;
1569 let resp = self
1570 .config
1571 .http_client()
1572 .get(url)
1573 .send()
1574 .await
1575 .map_err(SdkError::Http)?;
1576
1577 let status = resp.status();
1578 let body = resp.text().await.map_err(SdkError::Http)?;
1579
1580 if !status.is_success() {
1581 return Err(SdkError::Api { status, body });
1582 }
1583 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1584 }
1585
1586 pub async fn list_payments(&self) -> Result<ListPaymentsResponse, SdkError> {
1589 let url = self.config.admin().base_url.join("billing/payments")?;
1590 let resp = self
1591 .config
1592 .http_client()
1593 .get(url)
1594 .send()
1595 .await
1596 .map_err(SdkError::Http)?;
1597
1598 let status = resp.status();
1599 let body = resp.text().await.map_err(SdkError::Http)?;
1600
1601 if !status.is_success() {
1602 return Err(SdkError::Api { status, body });
1603 }
1604 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1605 }
1606
1607 pub async fn bulk_update_endpoint_status(
1611 &self,
1612 params: &BulkUpdateEndpointStatusRequest,
1613 ) -> Result<BulkUpdateEndpointStatusResponse, SdkError> {
1614 if params.ids.is_empty() {
1615 return Err(SdkError::Config(
1616 "bulk_update_endpoint_status requires at least one id".into(),
1617 ));
1618 }
1619 let url = self.config.admin().base_url.join("endpoints/bulk/status")?;
1620 let resp = self
1621 .config
1622 .http_client()
1623 .post(url)
1624 .json(params)
1625 .send()
1626 .await
1627 .map_err(SdkError::Http)?;
1628
1629 let status = resp.status();
1630 let body = resp.text().await.map_err(SdkError::Http)?;
1631
1632 if !status.is_success() {
1633 return Err(SdkError::Api { status, body });
1634 }
1635 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1636 }
1637
1638 pub async fn bulk_add_tag(
1642 &self,
1643 params: &BulkAddTagRequest,
1644 ) -> Result<BulkAddTagResponse, SdkError> {
1645 if params.ids.is_empty() {
1646 return Err(SdkError::Config(
1647 "bulk_add_tag requires at least one id".into(),
1648 ));
1649 }
1650 let url = self.config.admin().base_url.join("endpoints/bulk/tags")?;
1651 let resp = self
1652 .config
1653 .http_client()
1654 .post(url)
1655 .json(params)
1656 .send()
1657 .await
1658 .map_err(SdkError::Http)?;
1659
1660 let status = resp.status();
1661 let body = resp.text().await.map_err(SdkError::Http)?;
1662
1663 if !status.is_success() {
1664 return Err(SdkError::Api { status, body });
1665 }
1666 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1667 }
1668
1669 pub async fn bulk_remove_tag(
1672 &self,
1673 params: &BulkRemoveTagRequest,
1674 ) -> Result<BulkRemoveTagResponse, SdkError> {
1675 if params.ids.is_empty() {
1679 return Err(SdkError::Config(
1680 "bulk_remove_tag requires at least one id".into(),
1681 ));
1682 }
1683 let url = self.config.admin().base_url.join("endpoints/bulk/tags")?;
1684 let resp = self
1685 .config
1686 .http_client()
1687 .delete(url)
1688 .json(params)
1689 .send()
1690 .await
1691 .map_err(SdkError::Http)?;
1692
1693 let status = resp.status();
1694 let body = resp.text().await.map_err(SdkError::Http)?;
1695
1696 if !status.is_success() {
1697 return Err(SdkError::Api { status, body });
1698 }
1699 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1700 }
1701
1702 pub async fn list_tags(&self) -> Result<ListTagsResponse, SdkError> {
1705 let url = self.config.admin().base_url.join("endpoints/tags")?;
1706 let resp = self
1707 .config
1708 .http_client()
1709 .get(url)
1710 .send()
1711 .await
1712 .map_err(SdkError::Http)?;
1713
1714 let status = resp.status();
1715 let body = resp.text().await.map_err(SdkError::Http)?;
1716
1717 if !status.is_success() {
1718 return Err(SdkError::Api { status, body });
1719 }
1720 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1721 }
1722
1723 pub async fn rename_tag(
1726 &self,
1727 id: i32,
1728 params: &RenameTagRequest,
1729 ) -> Result<RenameTagResponse, SdkError> {
1730 let url = self
1731 .config
1732 .admin()
1733 .base_url
1734 .join(&format!("endpoints/tags/{}", id))?;
1735 let resp = self
1736 .config
1737 .http_client()
1738 .patch(url)
1739 .json(params)
1740 .send()
1741 .await
1742 .map_err(SdkError::Http)?;
1743
1744 let status = resp.status();
1745 let body = resp.text().await.map_err(SdkError::Http)?;
1746
1747 if !status.is_success() {
1748 return Err(SdkError::Api { status, body });
1749 }
1750 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1751 }
1752
1753 pub async fn delete_account_tag(&self, id: i32) -> Result<DeleteAccountTagResponse, SdkError> {
1758 let url = self
1759 .config
1760 .admin()
1761 .base_url
1762 .join(&format!("endpoints/tags/{}", id))?;
1763 let resp = self
1764 .config
1765 .http_client()
1766 .delete(url)
1767 .send()
1768 .await
1769 .map_err(SdkError::Http)?;
1770
1771 let status = resp.status();
1772 let body = resp.text().await.map_err(SdkError::Http)?;
1773
1774 if !status.is_success() {
1775 return Err(SdkError::Api { status, body });
1776 }
1777 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1778 }
1779
1780 pub async fn get_usage_by_tag(
1784 &self,
1785 params: &GetUsageRequest,
1786 ) -> Result<GetUsageByTagResponse, SdkError> {
1787 let url = self.config.admin().base_url.join("usage/rpc/by-tag")?;
1788 let resp = self
1789 .config
1790 .http_client()
1791 .get(url)
1792 .query(params)
1793 .send()
1794 .await
1795 .map_err(SdkError::Http)?;
1796
1797 let status = resp.status();
1798 let body = resp.text().await.map_err(SdkError::Http)?;
1799
1800 if !status.is_success() {
1801 return Err(SdkError::Api { status, body });
1802 }
1803 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1804 }
1805
1806 pub async fn get_endpoint_security(
1811 &self,
1812 id: &str,
1813 ) -> Result<GetEndpointSecurityResponse, SdkError> {
1814 let url = self
1815 .config
1816 .admin()
1817 .base_url
1818 .join(&format!("endpoints/{}/security", id))?;
1819 let resp = self
1820 .config
1821 .http_client()
1822 .get(url)
1823 .send()
1824 .await
1825 .map_err(SdkError::Http)?;
1826
1827 let status = resp.status();
1828 let body = resp.text().await.map_err(SdkError::Http)?;
1829
1830 if !status.is_success() {
1831 return Err(SdkError::Api { status, body });
1832 }
1833 serde_json::from_str(&body).map_err(|source| SdkError::Decode { source, body })
1834 }
1835}
1836
1837fn endpoints_query(params: &GetEndpointsRequest) -> Vec<(&'static str, String)> {
1838 let mut q: Vec<(&'static str, String)> = Vec::new();
1839 if let Some(v) = params.limit {
1840 q.push(("limit", v.to_string()));
1841 }
1842 if let Some(v) = params.offset {
1843 q.push(("offset", v.to_string()));
1844 }
1845 if let Some(ref v) = params.search {
1846 q.push(("search", v.clone()));
1847 }
1848 if let Some(ref v) = params.sort_by {
1849 q.push(("sort_by", v.clone()));
1850 }
1851 if let Some(ref v) = params.sort_direction {
1852 q.push(("sort_direction", v.clone()));
1853 }
1854 if let Some(ref list) = params.networks {
1855 for item in list {
1856 q.push(("networks[]", item.clone()));
1857 }
1858 }
1859 if let Some(ref list) = params.statuses {
1860 for item in list {
1861 q.push(("statuses[]", item.clone()));
1862 }
1863 }
1864 if let Some(ref list) = params.labels {
1865 for item in list {
1866 q.push(("labels[]", item.clone()));
1867 }
1868 }
1869 if let Some(v) = params.dedicated {
1870 q.push(("dedicated", v.to_string()));
1871 }
1872 if let Some(v) = params.is_flat_rate {
1873 q.push(("is_flat_rate", v.to_string()));
1874 }
1875 if let Some(ref list) = params.tag_ids {
1876 for item in list {
1877 q.push(("tag_ids[]", item.to_string()));
1878 }
1879 }
1880 if let Some(ref list) = params.tag_labels {
1881 for item in list {
1882 q.push(("tag_labels[]", item.clone()));
1883 }
1884 }
1885 q
1886}
1887
1888#[cfg(test)]
1889#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
1890mod tests {
1891 use super::*;
1892 use crate::{AdminConfig, QuicknodeSdk, SdkFullConfig};
1893 use wiremock::matchers::{method, path, query_param};
1894 use wiremock::{Mock, MockServer, ResponseTemplate};
1895
1896 fn make_sdk(base_url: String) -> QuicknodeSdk {
1897 QuicknodeSdk::new(&SdkFullConfig {
1898 api_key: "test-key".to_string(),
1899 http: None,
1900 admin: Some(AdminConfig {
1901 base_url: Some(base_url),
1902 }),
1903 streams: None,
1904 webhooks: None,
1905 kvstore: None,
1906 })
1907 .unwrap()
1908 }
1909
1910 #[tokio::test]
1911 async fn get_endpoints_success() {
1912 let server = MockServer::start().await;
1913
1914 Mock::given(method("GET"))
1915 .and(path("/endpoints"))
1916 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
1917 "data": [
1918 {
1919 "id": "abc123",
1920 "name": "aged-intensive-patron",
1921 "label": "My Endpoint",
1922 "status": "active",
1923 "chain": "ethereum",
1924 "network": "mainnet",
1925 "is_dedicated": false,
1926 "is_flat_rate": true,
1927 "http_url": "https://example.quicknode.pro/abc123",
1928 "wss_url": null,
1929 "tags": []
1930 }
1931 ],
1932 "pagination": {
1933 "total": 1,
1934 "limit": 20,
1935 "offset": 0
1936 },
1937 "error": null
1938 })))
1939 .mount(&server)
1940 .await;
1941
1942 let sdk = make_sdk(format!("{}/", server.uri()));
1943 let resp = sdk
1944 .admin
1945 .get_endpoints(&GetEndpointsRequest::default())
1946 .await
1947 .unwrap();
1948
1949 assert_eq!(resp.data.len(), 1);
1950 assert_eq!(resp.data[0].id, "abc123");
1951 assert_eq!(resp.data[0].name, "aged-intensive-patron");
1952 assert_eq!(resp.data[0].status, "active");
1953 assert_eq!(resp.data[0].chain, "ethereum");
1954 assert!(!resp.data[0].is_dedicated);
1955 assert!(resp.data[0].is_flat_rate);
1956 let pagination = resp.pagination.expect("pagination present");
1957 assert_eq!(pagination.total, 1);
1958 assert_eq!(pagination.limit, 20);
1959 assert_eq!(pagination.offset, 0);
1960 }
1961
1962 #[tokio::test]
1963 async fn get_endpoints_sends_search_and_filter_params() {
1964 let server = MockServer::start().await;
1965
1966 Mock::given(method("GET"))
1967 .and(path("/endpoints"))
1968 .and(query_param("search", "intensive"))
1969 .and(query_param("networks[]", "mainnet"))
1970 .and(query_param("statuses[]", "active"))
1971 .and(query_param("dedicated", "true"))
1972 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
1973 "data": [],
1974 "error": null
1975 })))
1976 .mount(&server)
1977 .await;
1978
1979 let sdk = make_sdk(format!("{}/", server.uri()));
1980 let params = GetEndpointsRequest {
1981 search: Some("intensive".to_string()),
1982 networks: Some(vec!["mainnet".to_string()]),
1983 statuses: Some(vec!["active".to_string()]),
1984 dedicated: Some(true),
1985 ..Default::default()
1986 };
1987 let resp = sdk.admin.get_endpoints(¶ms).await.unwrap();
1988
1989 assert_eq!(resp.data.len(), 0);
1990 }
1991
1992 #[tokio::test]
1993 async fn get_endpoints_api_error() {
1994 let server = MockServer::start().await;
1995
1996 Mock::given(method("GET"))
1997 .and(path("/endpoints"))
1998 .respond_with(ResponseTemplate::new(401).set_body_string("Unauthorized"))
1999 .mount(&server)
2000 .await;
2001
2002 let sdk = make_sdk(format!("{}/", server.uri()));
2003 let err = sdk
2004 .admin
2005 .get_endpoints(&GetEndpointsRequest::default())
2006 .await
2007 .unwrap_err();
2008
2009 match err {
2010 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 401),
2011 other => panic!("expected SdkError::Api, got {:?}", other),
2012 }
2013 }
2014
2015 #[tokio::test]
2016 async fn get_endpoints_sends_query_params() {
2017 let server = MockServer::start().await;
2018
2019 Mock::given(method("GET"))
2020 .and(path("/endpoints"))
2021 .and(query_param("limit", "10"))
2022 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2023 "data": [],
2024 "error": null
2025 })))
2026 .mount(&server)
2027 .await;
2028
2029 let sdk = make_sdk(format!("{}/", server.uri()));
2030 let params = GetEndpointsRequest {
2031 limit: Some(10),
2032 ..Default::default()
2033 };
2034 let resp = sdk.admin.get_endpoints(¶ms).await.unwrap();
2035
2036 assert_eq!(resp.data.len(), 0);
2037 }
2038
2039 #[tokio::test]
2040 async fn get_endpoints_base_url_without_trailing_slash() {
2041 let server = MockServer::start().await;
2042
2043 Mock::given(method("GET"))
2044 .and(path("/endpoints"))
2045 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2046 "data": [],
2047 "error": null
2048 })))
2049 .mount(&server)
2050 .await;
2051
2052 let base_url_no_slash = server.uri();
2053 let sdk = make_sdk(base_url_no_slash);
2054 let resp = sdk
2055 .admin
2056 .get_endpoints(&GetEndpointsRequest::default())
2057 .await
2058 .unwrap();
2059
2060 assert_eq!(resp.data.len(), 0);
2061 }
2062
2063 #[tokio::test]
2064 async fn create_endpoint_success() {
2065 let server = MockServer::start().await;
2066
2067 Mock::given(method("POST"))
2068 .and(path("/endpoints"))
2069 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2070 "data": {
2071 "id": "ep123",
2072 "label": null,
2073 "status": "active",
2074 "chain": "ethereum",
2075 "network": "mainnet",
2076 "http_url": "https://example.quicknode.pro/ep123",
2077 "wss_url": null,
2078 "security": {
2079 "options": { "tokens": true, "jwts": false, "domainMasks": false, "ips": false, "referrers": false, "requestFilters": false },
2080 "tokens": [{"id": "tok1", "token": "abc123"}],
2081 "jwts": null,
2082 "referrers": null,
2083 "domain_masks": null,
2084 "ips": null,
2085 "request_filters": null
2086 },
2087 "rate_limits": null,
2088 "tags": []
2089 },
2090 "error": null
2091 })))
2092 .mount(&server)
2093 .await;
2094
2095 let sdk = make_sdk(format!("{}/", server.uri()));
2096 let resp = sdk
2097 .admin
2098 .create_endpoint(&CreateEndpointRequest::default())
2099 .await
2100 .unwrap();
2101
2102 assert_eq!(resp.data.id, "ep123");
2103 assert_eq!(resp.data.chain, "ethereum");
2104 assert_eq!(resp.data.network, "mainnet");
2105 let security = resp.data.security.unwrap();
2106 assert!(security.tokens.unwrap().len() == 1);
2107 assert!(security.jwts.is_none());
2108 }
2109
2110 #[tokio::test]
2111 async fn create_endpoint_api_error() {
2112 let server = MockServer::start().await;
2113
2114 Mock::given(method("POST"))
2115 .and(path("/endpoints"))
2116 .respond_with(ResponseTemplate::new(400).set_body_string("Bad Request"))
2117 .mount(&server)
2118 .await;
2119
2120 let sdk = make_sdk(format!("{}/", server.uri()));
2121 let err = sdk
2122 .admin
2123 .create_endpoint(&CreateEndpointRequest::default())
2124 .await
2125 .unwrap_err();
2126
2127 match err {
2128 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 400),
2129 other => panic!("expected SdkError::Api, got {:?}", other),
2130 }
2131 }
2132
2133 #[tokio::test]
2134 async fn create_endpoint_sends_body() {
2135 use wiremock::matchers::body_json;
2136
2137 let server = MockServer::start().await;
2138
2139 Mock::given(method("POST"))
2140 .and(path("/endpoints"))
2141 .and(body_json(serde_json::json!({
2142 "chain": "solana",
2143 "network": "mainnet-beta"
2144 })))
2145 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2146 "data": {
2147 "id": "ep456",
2148 "label": null,
2149 "status": "active",
2150 "chain": "solana",
2151 "network": "mainnet-beta",
2152 "http_url": "https://example.quicknode.pro/ep456",
2153 "wss_url": null,
2154 "security": null,
2155 "rate_limits": null,
2156 "tags": []
2157 },
2158 "error": null
2159 })))
2160 .mount(&server)
2161 .await;
2162
2163 let sdk = make_sdk(format!("{}/", server.uri()));
2164 let params = CreateEndpointRequest {
2165 chain: Some("solana".to_string()),
2166 network: Some("mainnet-beta".to_string()),
2167 };
2168 let resp = sdk.admin.create_endpoint(¶ms).await.unwrap();
2169
2170 assert_eq!(resp.data.id, "ep456");
2171 assert_eq!(resp.data.chain, "solana");
2172 }
2173
2174 #[tokio::test]
2175 async fn show_endpoint_success() {
2176 let server = MockServer::start().await;
2177
2178 Mock::given(method("GET"))
2179 .and(path("/endpoints/ep123"))
2180 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2181 "data": {
2182 "id": "ep123",
2183 "label": null,
2184 "status": "active",
2185 "chain": "ethereum",
2186 "network": "mainnet",
2187 "http_url": "https://example.quicknode.pro/ep123",
2188 "wss_url": null,
2189 "security": null,
2190 "rate_limits": null,
2191 "tags": []
2192 },
2193 "error": null
2194 })))
2195 .mount(&server)
2196 .await;
2197
2198 let sdk = make_sdk(format!("{}/", server.uri()));
2199 let resp = sdk.admin.show_endpoint("ep123").await.unwrap();
2200 assert_eq!(resp.data.unwrap().id, "ep123");
2201 }
2202
2203 #[tokio::test]
2204 async fn show_endpoint_api_error() {
2205 let server = MockServer::start().await;
2206
2207 Mock::given(method("GET"))
2208 .and(path("/endpoints/ep123"))
2209 .respond_with(ResponseTemplate::new(404).set_body_string("Not Found"))
2210 .mount(&server)
2211 .await;
2212
2213 let sdk = make_sdk(format!("{}/", server.uri()));
2214 let err = sdk.admin.show_endpoint("ep123").await.unwrap_err();
2215 match err {
2216 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 404),
2217 other => panic!("expected SdkError::Api, got {:?}", other),
2218 }
2219 }
2220
2221 #[tokio::test]
2222 async fn update_endpoint_success() {
2223 let server = MockServer::start().await;
2224
2225 Mock::given(method("PATCH"))
2226 .and(path("/endpoints/ep123"))
2227 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2228 .mount(&server)
2229 .await;
2230
2231 let sdk = make_sdk(format!("{}/", server.uri()));
2232 sdk.admin
2233 .update_endpoint(
2234 "ep123",
2235 &UpdateEndpointRequest {
2236 label: Some("New Name".to_string()),
2237 },
2238 )
2239 .await
2240 .unwrap();
2241 }
2242
2243 #[tokio::test]
2244 async fn archive_endpoint_success() {
2245 let server = MockServer::start().await;
2246
2247 Mock::given(method("DELETE"))
2248 .and(path("/endpoints/ep123"))
2249 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2250 .mount(&server)
2251 .await;
2252
2253 let sdk = make_sdk(format!("{}/", server.uri()));
2254 sdk.admin.archive_endpoint("ep123").await.unwrap();
2255 }
2256
2257 #[tokio::test]
2258 async fn update_endpoint_status_success() {
2259 let server = MockServer::start().await;
2260
2261 Mock::given(method("PATCH"))
2262 .and(path("/endpoints/ep123/status"))
2263 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2264 "data": "paused",
2265 "error": null
2266 })))
2267 .mount(&server)
2268 .await;
2269
2270 let sdk = make_sdk(format!("{}/", server.uri()));
2271 let resp = sdk
2272 .admin
2273 .update_endpoint_status(
2274 "ep123",
2275 &UpdateEndpointStatusRequest {
2276 status: "paused".to_string(),
2277 },
2278 )
2279 .await
2280 .unwrap();
2281 assert_eq!(resp.data.unwrap(), "paused");
2282 }
2283
2284 #[tokio::test]
2285 async fn create_tag_success() {
2286 let server = MockServer::start().await;
2287
2288 Mock::given(method("POST"))
2289 .and(path("/endpoints/ep123/tags"))
2290 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2291 .mount(&server)
2292 .await;
2293
2294 let sdk = make_sdk(format!("{}/", server.uri()));
2295 sdk.admin
2296 .create_tag(
2297 "ep123",
2298 &CreateTagRequest {
2299 label: Some("my-tag".to_string()),
2300 },
2301 )
2302 .await
2303 .unwrap();
2304 }
2305
2306 #[tokio::test]
2307 async fn delete_tag_success() {
2308 let server = MockServer::start().await;
2309
2310 Mock::given(method("DELETE"))
2311 .and(path("/endpoints/ep123/tags/tag456"))
2312 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2313 .mount(&server)
2314 .await;
2315
2316 let sdk = make_sdk(format!("{}/", server.uri()));
2317 sdk.admin.delete_tag("ep123", "tag456").await.unwrap();
2318 }
2319
2320 #[tokio::test]
2321 async fn get_usage_success() {
2322 let server = MockServer::start().await;
2323
2324 Mock::given(method("GET"))
2325 .and(path("/usage/rpc"))
2326 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2327 "data": {
2328 "credits_used": 5000,
2329 "credits_remaining": 95000,
2330 "limit": 100000,
2331 "overages": null,
2332 "start_time": 1700000000,
2333 "end_time": 1702592000
2334 },
2335 "error": null
2336 })))
2337 .mount(&server)
2338 .await;
2339
2340 let sdk = make_sdk(format!("{}/", server.uri()));
2341 let resp = sdk
2342 .admin
2343 .get_usage(&GetUsageRequest::default())
2344 .await
2345 .unwrap();
2346 assert_eq!(resp.data.unwrap().credits_used, 5000);
2347 }
2348
2349 #[tokio::test]
2350 async fn get_usage_by_endpoint_success() {
2351 let server = MockServer::start().await;
2352
2353 Mock::given(method("GET"))
2354 .and(path("/usage/rpc/by-endpoint"))
2355 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2356 "data": {
2357 "endpoints": [{"name": "ep1", "chain": "eth", "network": "mainnet", "status": "active", "credits_used": 100, "label": null, "methods_breakdown": [], "requests": 50}],
2358 "start_time": 1700000000,
2359 "end_time": 1702592000
2360 },
2361 "error": null
2362 })))
2363 .mount(&server)
2364 .await;
2365
2366 let sdk = make_sdk(format!("{}/", server.uri()));
2367 let resp = sdk
2368 .admin
2369 .get_usage_by_endpoint(&GetUsageRequest::default())
2370 .await
2371 .unwrap();
2372 assert_eq!(resp.data.unwrap().endpoints.len(), 1);
2373 }
2374
2375 #[tokio::test]
2376 async fn get_usage_by_chain_success() {
2377 let server = MockServer::start().await;
2378
2379 Mock::given(method("GET"))
2380 .and(path("/usage/rpc/by-chain"))
2381 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2382 "data": {
2383 "chains": [{"name": "ethereum", "credits_used": 1000}],
2384 "start_time": 1700000000,
2385 "end_time": 1702592000
2386 },
2387 "error": null
2388 })))
2389 .mount(&server)
2390 .await;
2391
2392 let sdk = make_sdk(format!("{}/", server.uri()));
2393 let resp = sdk
2394 .admin
2395 .get_usage_by_chain(&GetUsageRequest::default())
2396 .await
2397 .unwrap();
2398 assert_eq!(resp.data.unwrap().chains[0].name, "ethereum");
2399 }
2400
2401 #[tokio::test]
2402 async fn get_endpoint_logs_success() {
2403 let server = MockServer::start().await;
2404
2405 Mock::given(method("GET"))
2406 .and(path("/endpoints/ep123/logs"))
2407 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2408 "data": [
2409 {
2410 "timestamp": "2025-04-29T12:39:25.543Z",
2411 "method": "eth_call",
2412 "network": "mainnet",
2413 "http_method": "POST",
2414 "status": 200,
2415 "error_code": null,
2416 "url": "/",
2417 "request_id": "abc-123",
2418 "details": null
2419 }
2420 ],
2421 "next_at": null
2422 })))
2423 .mount(&server)
2424 .await;
2425
2426 let sdk = make_sdk(format!("{}/", server.uri()));
2427 let params = GetEndpointLogsRequest {
2428 from: "2025-04-29T00:00:00Z".to_string(),
2429 to: "2025-04-29T23:59:59Z".to_string(),
2430 ..Default::default()
2431 };
2432 let resp = sdk.admin.get_endpoint_logs("ep123", ¶ms).await.unwrap();
2433 assert_eq!(resp.data.len(), 1);
2434 assert_eq!(resp.data[0].method.as_deref(), Some("eth_call"));
2435 }
2436
2437 #[tokio::test]
2438 async fn get_log_details_success() {
2439 let server = MockServer::start().await;
2440
2441 Mock::given(method("GET"))
2442 .and(path("/endpoints/ep123/log_details"))
2443 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2444 "data": {
2445 "request": "{\"method\":\"eth_call\"}",
2446 "response": "{\"result\":\"0x1\"}"
2447 }
2448 })))
2449 .mount(&server)
2450 .await;
2451
2452 let sdk = make_sdk(format!("{}/", server.uri()));
2453 let resp = sdk.admin.get_log_details("ep123", "abc-123").await.unwrap();
2454 assert!(resp.data.is_some());
2455 }
2456
2457 #[tokio::test]
2458 async fn get_security_options_success() {
2459 let server = MockServer::start().await;
2460
2461 Mock::given(method("GET"))
2462 .and(path("/endpoints/ep123/security_options"))
2463 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2464 "data": [{"option": "tokens", "status": "enabled", "value": null}],
2465 "error": null
2466 })))
2467 .mount(&server)
2468 .await;
2469
2470 let sdk = make_sdk(format!("{}/", server.uri()));
2471 let resp = sdk.admin.get_security_options("ep123").await.unwrap();
2472 assert_eq!(resp.data.len(), 1);
2473 assert_eq!(resp.data[0].option, "tokens");
2474 }
2475
2476 #[tokio::test]
2477 async fn update_security_options_success() {
2478 let server = MockServer::start().await;
2479
2480 Mock::given(method("PATCH"))
2481 .and(path("/endpoints/ep123/security_options"))
2482 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2483 "data": [{"option": "tokens", "status": "disabled", "value": null}],
2484 "error": null
2485 })))
2486 .mount(&server)
2487 .await;
2488
2489 let sdk = make_sdk(format!("{}/", server.uri()));
2490 let params = UpdateSecurityOptionsRequest {
2491 options: SecurityOptionsUpdate {
2492 tokens: Some("disabled".to_string()),
2493 ..Default::default()
2494 },
2495 };
2496 let resp = sdk
2497 .admin
2498 .update_security_options("ep123", ¶ms)
2499 .await
2500 .unwrap();
2501 assert_eq!(resp.data[0].status, "disabled");
2502 }
2503
2504 #[tokio::test]
2505 async fn create_token_success() {
2506 let server = MockServer::start().await;
2507
2508 Mock::given(method("POST"))
2509 .and(path("/endpoints/ep123/security/tokens"))
2510 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2511 .mount(&server)
2512 .await;
2513
2514 let sdk = make_sdk(format!("{}/", server.uri()));
2515 sdk.admin.create_token("ep123").await.unwrap();
2516 }
2517
2518 #[tokio::test]
2519 async fn delete_token_success() {
2520 let server = MockServer::start().await;
2521
2522 Mock::given(method("DELETE"))
2523 .and(path("/endpoints/ep123/security/tokens/tok1"))
2524 .respond_with(
2525 ResponseTemplate::new(200)
2526 .set_body_json(serde_json::json!({"data": true, "error": null})),
2527 )
2528 .mount(&server)
2529 .await;
2530
2531 let sdk = make_sdk(format!("{}/", server.uri()));
2532 let resp = sdk.admin.delete_token("ep123", "tok1").await.unwrap();
2533 assert_eq!(resp.data, Some(true));
2534 }
2535
2536 #[tokio::test]
2537 async fn create_referrer_success() {
2538 let server = MockServer::start().await;
2539
2540 Mock::given(method("POST"))
2541 .and(path("/endpoints/ep123/security/referrers"))
2542 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2543 .mount(&server)
2544 .await;
2545
2546 let sdk = make_sdk(format!("{}/", server.uri()));
2547 sdk.admin
2548 .create_referrer(
2549 "ep123",
2550 &CreateReferrerRequest {
2551 referrer: Some("example.com".to_string()),
2552 },
2553 )
2554 .await
2555 .unwrap();
2556 }
2557
2558 #[tokio::test]
2559 async fn enable_disable_multichain_success() {
2560 let server = MockServer::start().await;
2561
2562 Mock::given(method("POST"))
2563 .and(path("/endpoints/ep123/enable_multichain"))
2564 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2565 .mount(&server)
2566 .await;
2567
2568 Mock::given(method("POST"))
2569 .and(path("/endpoints/ep123/disable_multichain"))
2570 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2571 .mount(&server)
2572 .await;
2573
2574 let sdk = make_sdk(format!("{}/", server.uri()));
2575 sdk.admin.enable_multichain("ep123").await.unwrap();
2576 sdk.admin.disable_multichain("ep123").await.unwrap();
2577 }
2578
2579 #[tokio::test]
2580 async fn create_or_update_ip_custom_header_success() {
2581 let server = MockServer::start().await;
2582
2583 Mock::given(method("PATCH"))
2584 .and(path("/endpoints/ep123/ip_custom_header"))
2585 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2586 "data": {"header_name": "CF-Connecting-IP"},
2587 "error": null
2588 })))
2589 .mount(&server)
2590 .await;
2591
2592 let sdk = make_sdk(format!("{}/", server.uri()));
2593 let params = CreateOrUpdateIpCustomHeaderRequest {
2594 header_name: "CF-Connecting-IP".to_string(),
2595 };
2596 let resp = sdk
2597 .admin
2598 .create_or_update_ip_custom_header("ep123", ¶ms)
2599 .await
2600 .unwrap();
2601 assert_eq!(resp.data.unwrap().header_name, "CF-Connecting-IP");
2602 }
2603
2604 #[tokio::test]
2605 async fn get_method_rate_limits_success() {
2606 let server = MockServer::start().await;
2607
2608 Mock::given(method("GET"))
2609 .and(path("/endpoints/ep123/method-rate-limits"))
2610 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2611 "data": {
2612 "rate_limiters": [
2613 {"id": "rl1", "interval": "second", "methods": ["eth_call"], "rate": 10, "status": "enabled", "created": "2024-01-01T00:00:00Z"}
2614 ]
2615 },
2616 "error": null
2617 })))
2618 .mount(&server)
2619 .await;
2620
2621 let sdk = make_sdk(format!("{}/", server.uri()));
2622 let resp = sdk.admin.get_method_rate_limits("ep123").await.unwrap();
2623 assert_eq!(resp.data.unwrap().rate_limiters.len(), 1);
2624 }
2625
2626 #[tokio::test]
2627 async fn create_method_rate_limit_success() {
2628 let server = MockServer::start().await;
2629
2630 Mock::given(method("POST"))
2631 .and(path("/endpoints/ep123/method-rate-limits"))
2632 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2633 "data": {"id": "rl1", "interval": "second", "methods": ["eth_call"], "rate": 10, "status": "enabled", "created": "2024-01-01T00:00:00Z"},
2634 "error": null
2635 })))
2636 .mount(&server)
2637 .await;
2638
2639 let sdk = make_sdk(format!("{}/", server.uri()));
2640 let params = CreateMethodRateLimitRequest {
2641 interval: "second".to_string(),
2642 methods: vec!["eth_call".to_string()],
2643 rate: 10,
2644 };
2645 let resp = sdk
2646 .admin
2647 .create_method_rate_limit("ep123", ¶ms)
2648 .await
2649 .unwrap();
2650 assert_eq!(resp.data.unwrap().id, "rl1");
2651 }
2652
2653 #[tokio::test]
2654 async fn update_method_rate_limit_success() {
2655 let server = MockServer::start().await;
2656
2657 Mock::given(method("PATCH"))
2658 .and(path("/endpoints/ep123/method-rate-limits/rl1"))
2659 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2660 "data": {"id": "rl1", "interval": "day", "methods": ["eth_call"], "rate": 30, "status": "enabled", "created": "2024-01-01T00:00:00Z"},
2661 "error": null
2662 })))
2663 .mount(&server)
2664 .await;
2665
2666 let sdk = make_sdk(format!("{}/", server.uri()));
2667 let params = UpdateMethodRateLimitRequest {
2668 rate: Some(30),
2669 ..Default::default()
2670 };
2671 let resp = sdk
2672 .admin
2673 .update_method_rate_limit("ep123", "rl1", ¶ms)
2674 .await
2675 .unwrap();
2676 assert_eq!(resp.data.unwrap().rate, 30);
2677 }
2678
2679 #[tokio::test]
2680 async fn delete_method_rate_limit_success() {
2681 let server = MockServer::start().await;
2682
2683 Mock::given(method("DELETE"))
2684 .and(path("/endpoints/ep123/method-rate-limits/rl1"))
2685 .respond_with(
2686 ResponseTemplate::new(200)
2687 .set_body_json(serde_json::json!({"data": "deleted", "error": null})),
2688 )
2689 .mount(&server)
2690 .await;
2691
2692 let sdk = make_sdk(format!("{}/", server.uri()));
2693 sdk.admin
2694 .delete_method_rate_limit("ep123", "rl1")
2695 .await
2696 .unwrap();
2697 }
2698
2699 #[tokio::test]
2700 async fn update_rate_limits_success() {
2701 let server = MockServer::start().await;
2702
2703 Mock::given(method("PATCH"))
2704 .and(path("/endpoints/ep123/rate-limits"))
2705 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({})))
2706 .mount(&server)
2707 .await;
2708
2709 let sdk = make_sdk(format!("{}/", server.uri()));
2710 let params = UpdateRateLimitsRequest {
2711 rate_limits: RateLimitSettings {
2712 rps: Some(100),
2713 rpm: None,
2714 rpd: None,
2715 },
2716 };
2717 sdk.admin
2718 .update_rate_limits("ep123", ¶ms)
2719 .await
2720 .unwrap();
2721 }
2722
2723 #[tokio::test]
2724 async fn get_rate_limits_success() {
2725 let server = MockServer::start().await;
2726
2727 Mock::given(method("GET"))
2728 .and(path("/endpoints/ep123/rate-limits"))
2729 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2730 "data": {
2731 "rate_limits": [
2732 {"bucket": "rps", "rate_limit": 100, "source": "plan_default"},
2733 {"bucket": "rpm", "rate_limit": 6000, "source": "user_override", "id": "ovr-1"}
2734 ]
2735 },
2736 "error": null
2737 })))
2738 .mount(&server)
2739 .await;
2740
2741 let sdk = make_sdk(format!("{}/", server.uri()));
2742 let resp = sdk.admin.get_rate_limits("ep123").await.unwrap();
2743 let rows = resp.data.unwrap().rate_limits;
2744 assert_eq!(rows.len(), 2);
2745 assert_eq!(rows[0].source, "plan_default");
2746 assert!(rows[0].id.is_none());
2747 assert_eq!(rows[1].source, "user_override");
2748 assert_eq!(rows[1].rate_limit, 6000);
2749 assert_eq!(rows[1].id.as_deref(), Some("ovr-1"));
2750 }
2751
2752 #[tokio::test]
2753 async fn get_rate_limits_api_error() {
2754 let server = MockServer::start().await;
2755
2756 Mock::given(method("GET"))
2757 .and(path("/endpoints/missing/rate-limits"))
2758 .respond_with(ResponseTemplate::new(404).set_body_string("not found"))
2759 .mount(&server)
2760 .await;
2761
2762 let sdk = make_sdk(format!("{}/", server.uri()));
2763 let err = sdk.admin.get_rate_limits("missing").await.unwrap_err();
2764 match err {
2765 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 404),
2766 other => panic!("expected SdkError::Api, got {:?}", other),
2767 }
2768 }
2769
2770 #[tokio::test]
2771 async fn delete_rate_limit_override_success() {
2772 let server = MockServer::start().await;
2773
2774 Mock::given(method("DELETE"))
2775 .and(path("/endpoints/ep123/rate-limits/ovr-1"))
2776 .respond_with(ResponseTemplate::new(200).set_body_string(""))
2777 .mount(&server)
2778 .await;
2779
2780 let sdk = make_sdk(format!("{}/", server.uri()));
2781 sdk.admin
2782 .delete_rate_limit_override("ep123", "ovr-1")
2783 .await
2784 .unwrap();
2785 }
2786
2787 #[tokio::test]
2788 async fn delete_rate_limit_override_not_found() {
2789 let server = MockServer::start().await;
2790
2791 Mock::given(method("DELETE"))
2792 .and(path("/endpoints/ep123/rate-limits/bogus"))
2793 .respond_with(ResponseTemplate::new(404).set_body_string("override not found"))
2794 .mount(&server)
2795 .await;
2796
2797 let sdk = make_sdk(format!("{}/", server.uri()));
2798 let err = sdk
2799 .admin
2800 .delete_rate_limit_override("ep123", "bogus")
2801 .await
2802 .unwrap_err();
2803 match err {
2804 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 404),
2805 other => panic!("expected SdkError::Api, got {:?}", other),
2806 }
2807 }
2808
2809 #[tokio::test]
2810 async fn get_endpoint_urls_success() {
2811 let server = MockServer::start().await;
2812
2813 Mock::given(method("GET"))
2814 .and(path("/endpoints/ep123/urls"))
2815 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2816 "data": {
2817 "http_url": "https://example.quiknode.pro/abc/",
2818 "wss_url": "wss://example.quiknode.pro/abc/",
2819 "multichain_urls": null
2820 },
2821 "error": null
2822 })))
2823 .mount(&server)
2824 .await;
2825
2826 let sdk = make_sdk(format!("{}/", server.uri()));
2827 let resp = sdk.admin.get_endpoint_urls("ep123").await.unwrap();
2828 let data = resp.data.unwrap();
2829 assert_eq!(data.http_url, "https://example.quiknode.pro/abc/");
2830 assert!(data.multichain_urls.is_none());
2831 }
2832
2833 #[tokio::test]
2834 async fn get_endpoint_urls_multichain() {
2835 let server = MockServer::start().await;
2836
2837 Mock::given(method("GET"))
2838 .and(path("/endpoints/ep123/urls"))
2839 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2840 "data": {
2841 "http_url": "https://example.quiknode.pro/abc/",
2842 "wss_url": null,
2843 "multichain_urls": {
2844 "ethereum-mainnet": {
2845 "http_url": "https://example.quiknode.pro/abc/eth/",
2846 "wss_url": "wss://example.quiknode.pro/abc/eth/"
2847 }
2848 }
2849 },
2850 "error": null
2851 })))
2852 .mount(&server)
2853 .await;
2854
2855 let sdk = make_sdk(format!("{}/", server.uri()));
2856 let resp = sdk.admin.get_endpoint_urls("ep123").await.unwrap();
2857 let data = resp.data.unwrap();
2858 let mc = data.multichain_urls.unwrap();
2859 assert_eq!(mc.len(), 1);
2860 assert_eq!(
2861 mc.get("ethereum-mainnet").unwrap().http_url,
2862 "https://example.quiknode.pro/abc/eth/"
2863 );
2864 }
2865
2866 #[tokio::test]
2867 async fn get_endpoint_metrics_success() {
2868 let server = MockServer::start().await;
2869
2870 Mock::given(method("GET"))
2871 .and(path("/endpoints/ep123/metrics"))
2872 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2873 "data": [{"data": [[1700000000, 42]], "tag": ["network", "mainnet"]}],
2874 "error": null
2875 })))
2876 .mount(&server)
2877 .await;
2878
2879 let sdk = make_sdk(format!("{}/", server.uri()));
2880 let params = GetEndpointMetricsRequest {
2881 period: "day".to_string(),
2882 metric: "credits_over_time".to_string(),
2883 };
2884 let resp = sdk
2885 .admin
2886 .get_endpoint_metrics("ep123", ¶ms)
2887 .await
2888 .unwrap();
2889 assert_eq!(resp.data.len(), 1);
2890 assert_eq!(
2891 resp.data[0].tag,
2892 vec!["network".to_string(), "mainnet".to_string()]
2893 );
2894 }
2895
2896 #[tokio::test]
2897 async fn get_account_metrics_success() {
2898 let server = MockServer::start().await;
2899
2900 Mock::given(method("GET"))
2901 .and(path("/metrics"))
2902 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2903 "data": [{"data": [[1700000000, 100]], "tag": "total"}],
2904 "error": null
2905 })))
2906 .mount(&server)
2907 .await;
2908
2909 let sdk = make_sdk(format!("{}/", server.uri()));
2910 let params = GetAccountMetricsRequest {
2911 period: "week".to_string(),
2912 metric: "credits_over_time".to_string(),
2913 percentile: None,
2914 };
2915 let resp = sdk.admin.get_account_metrics(¶ms).await.unwrap();
2916 assert_eq!(resp.data.len(), 1);
2917 assert_eq!(resp.data[0].tag, vec!["total".to_string()]);
2918 }
2919
2920 #[tokio::test]
2925 async fn get_account_metrics_decodes_tuple_tag() {
2926 let server = MockServer::start().await;
2927
2928 Mock::given(method("GET"))
2929 .and(path("/metrics"))
2930 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2931 "data": [
2932 {"tag": ["network", "arbitrum-mainnet"], "data": [[1779109200, 40]]},
2933 {"tag": ["network", "mainnet"], "data": [[1779116400, 40]]},
2934 {"tag": "p95", "data": [[1779116400, 12]]}
2935 ],
2936 "error": null
2937 })))
2938 .mount(&server)
2939 .await;
2940
2941 let sdk = make_sdk(format!("{}/", server.uri()));
2942 let params = GetAccountMetricsRequest {
2943 period: "day".to_string(),
2944 metric: "credits_over_time".to_string(),
2945 percentile: None,
2946 };
2947 let resp = sdk.admin.get_account_metrics(¶ms).await.unwrap();
2948 assert_eq!(resp.data.len(), 3);
2949 assert_eq!(
2950 resp.data[0].tag,
2951 vec!["network".to_string(), "arbitrum-mainnet".to_string()]
2952 );
2953 assert_eq!(
2954 resp.data[1].tag,
2955 vec!["network".to_string(), "mainnet".to_string()]
2956 );
2957 assert_eq!(resp.data[2].tag, vec!["p95".to_string()]);
2958 }
2959
2960 #[tokio::test]
2961 async fn list_chains_success() {
2962 let server = MockServer::start().await;
2963
2964 Mock::given(method("GET"))
2965 .and(path("/chains"))
2966 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2967 "data": [
2968 {
2969 "slug": "eth",
2970 "networks": [{"slug": "mainnet", "name": "Ethereum Mainnet", "chain_id": 1}],
2971 "is_select_chain": true
2972 }
2973 ],
2974 "error": null
2975 })))
2976 .mount(&server)
2977 .await;
2978
2979 let sdk = make_sdk(format!("{}/", server.uri()));
2980 let resp = sdk.admin.list_chains().await.unwrap();
2981 assert_eq!(resp.data.len(), 1);
2982 assert_eq!(resp.data[0].slug, "eth");
2983 assert_eq!(resp.data[0].networks[0].chain_id, Some(1));
2984 }
2985
2986 #[tokio::test]
2987 async fn list_invoices_success() {
2988 let server = MockServer::start().await;
2989
2990 Mock::given(method("GET"))
2991 .and(path("/billing/invoices"))
2992 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
2993 "data": {
2994 "invoices": [
2995 {
2996 "id": "inv123",
2997 "status": "paid",
2998 "billing_reason": "subscription",
2999 "lines": [{"description": "Pro plan", "amount": 4900}],
3000 "amount_due": 4900,
3001 "amount_paid": 4900,
3002 "period_start": 1700000000,
3003 "period_end": 1702592000,
3004 "created": 1700000000,
3005 "subtotal": 4900
3006 }
3007 ]
3008 },
3009 "error": null
3010 })))
3011 .mount(&server)
3012 .await;
3013
3014 let sdk = make_sdk(format!("{}/", server.uri()));
3015 let resp = sdk.admin.list_invoices().await.unwrap();
3016 let data = resp.data.unwrap();
3017 assert_eq!(data.invoices.len(), 1);
3018 assert_eq!(data.invoices[0].id, "inv123");
3019 }
3020
3021 #[tokio::test]
3022 async fn list_invoices_api_error() {
3023 let server = MockServer::start().await;
3024
3025 Mock::given(method("GET"))
3026 .and(path("/billing/invoices"))
3027 .respond_with(ResponseTemplate::new(401).set_body_string("Unauthorized"))
3028 .mount(&server)
3029 .await;
3030
3031 let sdk = make_sdk(format!("{}/", server.uri()));
3032 let err = sdk.admin.list_invoices().await.unwrap_err();
3033 match err {
3034 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 401),
3035 other => panic!("expected SdkError::Api, got {:?}", other),
3036 }
3037 }
3038
3039 #[tokio::test]
3040 async fn list_payments_success() {
3041 let server = MockServer::start().await;
3042
3043 Mock::given(method("GET"))
3044 .and(path("/billing/payments"))
3045 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3046 "data": {
3047 "payments": [
3048 {
3049 "amount": "49.00",
3050 "card_last_4": "4242",
3051 "created_at": "2024-01-01T00:00:00Z",
3052 "currency": "usd",
3053 "status": "succeeded",
3054 "marketplace_amount": "9.0"
3055 }
3056 ]
3057 },
3058 "error": null
3059 })))
3060 .mount(&server)
3061 .await;
3062
3063 let sdk = make_sdk(format!("{}/", server.uri()));
3064 let resp = sdk.admin.list_payments().await.unwrap();
3065 let data = resp.data.unwrap();
3066 assert_eq!(data.payments.len(), 1);
3067 assert_eq!(data.payments[0].currency, "usd");
3068 }
3069
3070 #[tokio::test]
3071 async fn list_teams_success() {
3072 let server = MockServer::start().await;
3073
3074 Mock::given(method("GET"))
3075 .and(path("/teams"))
3076 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3077 "data": [{"id": 1, "name": "Engineering", "members_count": 5, "users": []}],
3078 "error": null
3079 })))
3080 .mount(&server)
3081 .await;
3082
3083 let sdk = make_sdk(format!("{}/", server.uri()));
3084 let resp = sdk.admin.list_teams().await.unwrap();
3085 assert_eq!(resp.data.len(), 1);
3086 assert_eq!(resp.data[0].name, "Engineering");
3087 }
3088
3089 #[tokio::test]
3090 async fn list_teams_api_error() {
3091 let server = MockServer::start().await;
3092
3093 Mock::given(method("GET"))
3094 .and(path("/teams"))
3095 .respond_with(ResponseTemplate::new(401).set_body_string("Unauthorized"))
3096 .mount(&server)
3097 .await;
3098
3099 let sdk = make_sdk(format!("{}/", server.uri()));
3100 let err = sdk.admin.list_teams().await.unwrap_err();
3101 match err {
3102 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 401),
3103 other => panic!("expected SdkError::Api, got {:?}", other),
3104 }
3105 }
3106
3107 #[tokio::test]
3108 async fn create_team_success() {
3109 let server = MockServer::start().await;
3110
3111 Mock::given(method("POST"))
3112 .and(path("/teams"))
3113 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3114 "data": {"id": 42, "name": "New Team", "default_role": null, "members_count": 0},
3115 "error": null
3116 })))
3117 .mount(&server)
3118 .await;
3119
3120 let sdk = make_sdk(format!("{}/", server.uri()));
3121 let params = CreateTeamRequest {
3122 name: "New Team".to_string(),
3123 };
3124 let resp = sdk.admin.create_team(¶ms).await.unwrap();
3125 assert_eq!(resp.data.unwrap().id, 42);
3126 }
3127
3128 #[tokio::test]
3129 async fn get_team_success() {
3130 let server = MockServer::start().await;
3131
3132 Mock::given(method("GET"))
3133 .and(path("/teams/1"))
3134 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3135 "data": {
3136 "id": 1,
3137 "name": "Engineering",
3138 "default_role": "member",
3139 "members_count": 3,
3140 "users": [],
3141 "pending_invites": []
3142 },
3143 "error": null
3144 })))
3145 .mount(&server)
3146 .await;
3147
3148 let sdk = make_sdk(format!("{}/", server.uri()));
3149 let resp = sdk.admin.get_team(1).await.unwrap();
3150 assert_eq!(resp.data.unwrap().name, "Engineering");
3151 }
3152
3153 #[tokio::test]
3154 async fn delete_team_success() {
3155 let server = MockServer::start().await;
3156
3157 Mock::given(method("DELETE"))
3158 .and(path("/teams/1"))
3159 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3160 "data": {"message": "Team deleted"},
3161 "error": null
3162 })))
3163 .mount(&server)
3164 .await;
3165
3166 let sdk = make_sdk(format!("{}/", server.uri()));
3167 let resp = sdk.admin.delete_team(1).await.unwrap();
3168 assert!(resp.data.is_some());
3169 }
3170
3171 #[tokio::test]
3172 async fn list_team_endpoints_success() {
3173 let server = MockServer::start().await;
3174
3175 Mock::given(method("GET"))
3176 .and(path("/teams/1/endpoints"))
3177 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3178 "data": [{"id": 10, "subdomain": "abc123", "chain": "ethereum", "network": "mainnet"}],
3179 "error": null
3180 })))
3181 .mount(&server)
3182 .await;
3183
3184 let sdk = make_sdk(format!("{}/", server.uri()));
3185 let resp = sdk.admin.list_team_endpoints(1).await.unwrap();
3186 assert_eq!(resp.data.len(), 1);
3187 assert_eq!(resp.data[0].subdomain, "abc123");
3188 }
3189
3190 #[tokio::test]
3191 async fn update_team_endpoints_success() {
3192 let server = MockServer::start().await;
3193
3194 Mock::given(method("PATCH"))
3195 .and(path("/teams/1/endpoints"))
3196 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3197 "data": {"success": true},
3198 "error": null
3199 })))
3200 .mount(&server)
3201 .await;
3202
3203 let sdk = make_sdk(format!("{}/", server.uri()));
3204 let params = UpdateTeamEndpointsRequest {
3205 endpoint_ids: vec!["ep1".to_string()],
3206 };
3207 let resp = sdk.admin.update_team_endpoints(1, ¶ms).await.unwrap();
3208 assert!(resp.data.unwrap().success.unwrap());
3209 }
3210
3211 #[tokio::test]
3215 async fn update_team_endpoints_empty_array_wire_body() {
3216 use wiremock::matchers::body_json;
3217 let server = MockServer::start().await;
3218 Mock::given(method("PATCH"))
3219 .and(path("/teams/1/endpoints"))
3220 .and(body_json(serde_json::json!({ "endpoint_ids": [] })))
3221 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3222 "data": {"success": true},
3223 "error": null
3224 })))
3225 .mount(&server)
3226 .await;
3227 let sdk = make_sdk(format!("{}/", server.uri()));
3228 let params = UpdateTeamEndpointsRequest {
3229 endpoint_ids: vec![],
3230 };
3231 sdk.admin.update_team_endpoints(1, ¶ms).await.unwrap();
3232 }
3233
3234 #[tokio::test]
3235 async fn invite_team_member_success() {
3236 let server = MockServer::start().await;
3237
3238 Mock::given(method("POST"))
3239 .and(path("/teams/1/members"))
3240 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3241 "data": {
3242 "id": 99,
3243 "email": "user@example.com",
3244 "full_name": null,
3245 "role": "member",
3246 "status": "pending",
3247 "created_at": null,
3248 "photo_url": null,
3249 "account_primary_user": null
3250 },
3251 "error": null
3252 })))
3253 .mount(&server)
3254 .await;
3255
3256 let sdk = make_sdk(format!("{}/", server.uri()));
3257 let params = InviteTeamMemberRequest {
3258 email: "user@example.com".to_string(),
3259 full_name: None,
3260 role: None,
3261 };
3262 let resp = sdk.admin.invite_team_member(1, ¶ms).await.unwrap();
3263 assert_eq!(resp.data.unwrap().email, "user@example.com");
3264 }
3265
3266 #[tokio::test]
3267 async fn remove_team_member_success() {
3268 let server = MockServer::start().await;
3269
3270 Mock::given(method("DELETE"))
3271 .and(path("/teams/1/members/99"))
3272 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3273 "data": {"message": "Member removed"},
3274 "error": null
3275 })))
3276 .mount(&server)
3277 .await;
3278
3279 let sdk = make_sdk(format!("{}/", server.uri()));
3280 let params = RemoveTeamMemberRequest { destroy_user: None };
3281 let resp = sdk.admin.remove_team_member(1, 99, ¶ms).await.unwrap();
3282 assert!(resp.data.is_some());
3283 }
3284
3285 #[tokio::test]
3286 async fn resend_team_invite_success() {
3287 let server = MockServer::start().await;
3288
3289 Mock::given(method("POST"))
3290 .and(path("/teams/1/members/99/resend_invite"))
3291 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3292 "data": {"message": "Invite resent"},
3293 "error": null
3294 })))
3295 .mount(&server)
3296 .await;
3297
3298 let sdk = make_sdk(format!("{}/", server.uri()));
3299 let resp = sdk.admin.resend_team_invite(1, 99).await.unwrap();
3300 assert!(resp.data.is_some());
3301 }
3302
3303 #[tokio::test]
3304 async fn bulk_update_endpoint_status_success() {
3305 let server = MockServer::start().await;
3306 Mock::given(method("POST"))
3307 .and(path("/endpoints/bulk/status"))
3308 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3309 "data": {
3310 "total": 2,
3311 "updated_count": 2,
3312 "failed_count": 0,
3313 "results": [
3314 { "id": "a", "success": true },
3315 { "id": "b", "success": true }
3316 ]
3317 }
3318 })))
3319 .mount(&server)
3320 .await;
3321
3322 let sdk = make_sdk(format!("{}/", server.uri()));
3323 let params = BulkUpdateEndpointStatusRequest {
3324 ids: vec!["a".to_string(), "b".to_string()],
3325 status: "paused".to_string(),
3326 };
3327 let resp = sdk
3328 .admin
3329 .bulk_update_endpoint_status(¶ms)
3330 .await
3331 .unwrap();
3332 let data = resp.data.expect("data present");
3333 assert_eq!(data.total, 2);
3334 assert_eq!(data.updated_count, 2);
3335 assert_eq!(data.results.len(), 2);
3336 }
3337
3338 #[tokio::test]
3339 async fn bulk_update_endpoint_status_api_error() {
3340 let server = MockServer::start().await;
3341 Mock::given(method("POST"))
3342 .and(path("/endpoints/bulk/status"))
3343 .respond_with(ResponseTemplate::new(400).set_body_string("bad request"))
3344 .mount(&server)
3345 .await;
3346
3347 let sdk = make_sdk(format!("{}/", server.uri()));
3348 let params = BulkUpdateEndpointStatusRequest {
3349 ids: vec!["a".to_string()],
3350 status: "paused".to_string(),
3351 };
3352 let err = sdk
3353 .admin
3354 .bulk_update_endpoint_status(¶ms)
3355 .await
3356 .unwrap_err();
3357 match err {
3358 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 400),
3359 other => panic!("expected Api, got {:?}", other),
3360 }
3361 }
3362
3363 #[tokio::test]
3364 async fn bulk_add_tag_success() {
3365 let server = MockServer::start().await;
3366 Mock::given(method("POST"))
3367 .and(path("/endpoints/bulk/tags"))
3368 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3369 "data": {
3370 "total": 1,
3371 "updated_count": 1,
3372 "failed_count": 0,
3373 "results": [{ "id": "a", "success": true }],
3374 "tag": { "tag_id": 7, "label": "prod" }
3375 }
3376 })))
3377 .mount(&server)
3378 .await;
3379
3380 let sdk = make_sdk(format!("{}/", server.uri()));
3381 let params = BulkAddTagRequest {
3382 ids: vec!["a".to_string()],
3383 label: "prod".to_string(),
3384 };
3385 let resp = sdk.admin.bulk_add_tag(¶ms).await.unwrap();
3386 let data = resp.data.expect("data present");
3387 assert_eq!(data.tag.tag_id, 7);
3388 assert_eq!(data.tag.label, "prod");
3389 }
3390
3391 #[tokio::test]
3392 async fn bulk_remove_tag_success() {
3393 let server = MockServer::start().await;
3394 Mock::given(method("DELETE"))
3395 .and(path("/endpoints/bulk/tags"))
3396 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3397 "data": {
3398 "total": 2,
3399 "updated_count": 2,
3400 "failed_count": 0,
3401 "results": [
3402 { "id": "a", "success": true },
3403 { "id": "b", "success": true }
3404 ]
3405 }
3406 })))
3407 .mount(&server)
3408 .await;
3409
3410 let sdk = make_sdk(format!("{}/", server.uri()));
3411 let params = BulkRemoveTagRequest {
3412 ids: vec!["a".to_string(), "b".to_string()],
3413 tag_id: 42,
3414 };
3415 let resp = sdk.admin.bulk_remove_tag(¶ms).await.unwrap();
3416 assert_eq!(resp.data.expect("data").updated_count, 2);
3417 }
3418
3419 #[test]
3420 fn endpoint_token_debug_is_redacted() {
3421 let t = EndpointToken {
3422 id: "tok_1".to_string(),
3423 token: "super-secret".to_string(),
3424 };
3425 let dbg = format!("{t:?}");
3426 assert!(dbg.contains("tok_1"));
3427 assert!(!dbg.contains("super-secret"));
3428 assert!(dbg.contains("[redacted]"));
3429 }
3430
3431 #[test]
3432 fn endpoint_jwt_debug_redacts_public_key() {
3433 let j = EndpointJwt {
3434 id: "jwt_1".to_string(),
3435 public_key: "-----BEGIN PUBLIC KEY-----\nAAAA\n-----END PUBLIC KEY-----".to_string(),
3436 kid: "kid1".to_string(),
3437 name: "myjwt".to_string(),
3438 };
3439 let dbg = format!("{j:?}");
3440 assert!(dbg.contains("jwt_1"));
3441 assert!(dbg.contains("kid1"));
3442 assert!(!dbg.contains("BEGIN PUBLIC KEY"));
3443 assert!(dbg.contains("[redacted]"));
3444 }
3445
3446 #[tokio::test]
3447 async fn bulk_methods_reject_empty_ids() {
3448 let sdk = make_sdk("http://127.0.0.1:1/".to_string());
3450
3451 let err = sdk
3452 .admin
3453 .bulk_update_endpoint_status(&BulkUpdateEndpointStatusRequest {
3454 ids: vec![],
3455 status: "paused".to_string(),
3456 })
3457 .await
3458 .unwrap_err();
3459 assert!(matches!(err, SdkError::Config(_)));
3460
3461 let err = sdk
3462 .admin
3463 .bulk_add_tag(&BulkAddTagRequest {
3464 ids: vec![],
3465 label: "x".to_string(),
3466 })
3467 .await
3468 .unwrap_err();
3469 assert!(matches!(err, SdkError::Config(_)));
3470
3471 let err = sdk
3472 .admin
3473 .bulk_remove_tag(&BulkRemoveTagRequest {
3474 ids: vec![],
3475 tag_id: 1,
3476 })
3477 .await
3478 .unwrap_err();
3479 assert!(matches!(err, SdkError::Config(_)));
3480 }
3481
3482 #[tokio::test]
3483 async fn list_tags_success() {
3484 let server = MockServer::start().await;
3485 Mock::given(method("GET"))
3486 .and(path("/endpoints/tags"))
3487 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3488 "data": {
3489 "tags": [
3490 { "id": 1, "label": "prod", "usage_count": 3 },
3491 { "id": 2, "label": "staging", "usage_count": 0 }
3492 ]
3493 },
3494 "error": null
3495 })))
3496 .mount(&server)
3497 .await;
3498
3499 let sdk = make_sdk(format!("{}/", server.uri()));
3500 let resp = sdk.admin.list_tags().await.unwrap();
3501 let data = resp.data.expect("data present");
3502 assert_eq!(data.tags.len(), 2);
3503 assert_eq!(data.tags[0].label, "prod");
3504 assert_eq!(data.tags[1].usage_count, 0);
3505 }
3506
3507 #[tokio::test]
3508 async fn list_tags_api_error() {
3509 let server = MockServer::start().await;
3510 Mock::given(method("GET"))
3511 .and(path("/endpoints/tags"))
3512 .respond_with(ResponseTemplate::new(500).set_body_string("oops"))
3513 .mount(&server)
3514 .await;
3515
3516 let sdk = make_sdk(format!("{}/", server.uri()));
3517 let err = sdk.admin.list_tags().await.unwrap_err();
3518 match err {
3519 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 500),
3520 other => panic!("expected Api, got {:?}", other),
3521 }
3522 }
3523
3524 #[tokio::test]
3525 async fn rename_tag_success() {
3526 let server = MockServer::start().await;
3527 Mock::given(method("PATCH"))
3528 .and(path("/endpoints/tags/7"))
3529 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3530 "data": { "id": 7, "label": "prod-v2", "usage_count": 3 },
3531 "error": null
3532 })))
3533 .mount(&server)
3534 .await;
3535
3536 let sdk = make_sdk(format!("{}/", server.uri()));
3537 let params = RenameTagRequest {
3538 label: "prod-v2".to_string(),
3539 };
3540 let resp = sdk.admin.rename_tag(7, ¶ms).await.unwrap();
3541 let tag = resp.data.expect("tag present");
3542 assert_eq!(tag.id, 7);
3543 assert_eq!(tag.label, "prod-v2");
3544 }
3545
3546 #[tokio::test]
3547 async fn delete_account_tag_success() {
3548 let server = MockServer::start().await;
3549 Mock::given(method("DELETE"))
3550 .and(path("/endpoints/tags/7"))
3551 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3552 "data": { "success": true },
3553 "error": null
3554 })))
3555 .mount(&server)
3556 .await;
3557
3558 let sdk = make_sdk(format!("{}/", server.uri()));
3559 let resp = sdk.admin.delete_account_tag(7).await.unwrap();
3560 assert!(resp.data.expect("data").success);
3561 }
3562
3563 #[tokio::test]
3564 async fn delete_account_tag_still_in_use() {
3565 let server = MockServer::start().await;
3566 Mock::given(method("DELETE"))
3567 .and(path("/endpoints/tags/7"))
3568 .respond_with(ResponseTemplate::new(400).set_body_string("tag still in use"))
3569 .mount(&server)
3570 .await;
3571
3572 let sdk = make_sdk(format!("{}/", server.uri()));
3573 let err = sdk.admin.delete_account_tag(7).await.unwrap_err();
3574 match err {
3575 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 400),
3576 other => panic!("expected Api, got {:?}", other),
3577 }
3578 }
3579
3580 #[tokio::test]
3581 async fn get_usage_by_tag_success() {
3582 let server = MockServer::start().await;
3583 Mock::given(method("GET"))
3584 .and(path("/usage/rpc/by-tag"))
3585 .and(query_param("start_time", "1700000000"))
3586 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3587 "data": {
3588 "tags": [
3589 { "tag_id": 1, "label": "prod", "credits_used": 1234, "requests": 10 },
3590 { "tag_id": null, "label": "untagged", "credits_used": 50, "requests": 2 }
3591 ],
3592 "start_time": 1700000000,
3593 "end_time": 1700003600
3594 },
3595 "error": null
3596 })))
3597 .mount(&server)
3598 .await;
3599
3600 let sdk = make_sdk(format!("{}/", server.uri()));
3601 let params = GetUsageRequest {
3602 start_time: Some(1_700_000_000),
3603 ..Default::default()
3604 };
3605 let resp = sdk.admin.get_usage_by_tag(¶ms).await.unwrap();
3606 let data = resp.data.expect("data present");
3607 assert_eq!(data.tags.len(), 2);
3608 assert_eq!(data.tags[0].tag_id, Some(1));
3609 assert_eq!(data.tags[1].tag_id, None);
3610 assert_eq!(data.tags[1].label, "untagged");
3611 }
3612
3613 #[tokio::test]
3614 async fn get_endpoint_security_success() {
3615 let server = MockServer::start().await;
3616 Mock::given(method("GET"))
3617 .and(path("/endpoints/abc123/security"))
3618 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
3619 "data": {
3620 "options": { "tokens": true, "ips": false },
3621 "tokens": [{ "id": "tok_1", "token": "secret" }],
3622 "jwts": [],
3623 "referrers": [],
3624 "domain_masks": [],
3625 "ips": [],
3626 "request_filters": []
3627 },
3628 "error": null
3629 })))
3630 .mount(&server)
3631 .await;
3632
3633 let sdk = make_sdk(format!("{}/", server.uri()));
3634 let resp = sdk.admin.get_endpoint_security("abc123").await.unwrap();
3635 let data = resp.data.expect("data present");
3636 let tokens = data.tokens.expect("tokens present");
3637 assert_eq!(tokens.len(), 1);
3638 assert_eq!(tokens[0].id, "tok_1");
3639 }
3640
3641 #[tokio::test]
3642 async fn get_endpoint_security_not_found() {
3643 let server = MockServer::start().await;
3644 Mock::given(method("GET"))
3645 .and(path("/endpoints/missing/security"))
3646 .respond_with(ResponseTemplate::new(404).set_body_string("not found"))
3647 .mount(&server)
3648 .await;
3649
3650 let sdk = make_sdk(format!("{}/", server.uri()));
3651 let err = sdk
3652 .admin
3653 .get_endpoint_security("missing")
3654 .await
3655 .unwrap_err();
3656 match err {
3657 SdkError::Api { status, .. } => assert_eq!(status.as_u16(), 404),
3658 other => panic!("expected Api, got {:?}", other),
3659 }
3660 }
3661
3662 #[test]
3663 fn negative_timeout_secs_returns_error() {
3664 use crate::{HttpConfig, SdkConfig, SdkFullConfig};
3665 let result = SdkConfig::new(&SdkFullConfig {
3666 api_key: "test-key".to_string(),
3667 http: Some(HttpConfig {
3668 timeout_secs: Some(-1),
3669 pool_max_idle_per_host: None,
3670 }),
3671 admin: None,
3672 streams: None,
3673 webhooks: None,
3674 kvstore: None,
3675 });
3676 assert!(matches!(result, Err(crate::errors::SdkError::Config(_))));
3677 }
3678}