Skip to content

Commit 58887ff

Browse files
Updated at mer 11 feb 2026, 16:02:25, CET
1 parent 9c034a2 commit 58887ff

9 files changed

Lines changed: 354 additions & 217 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ serde = { version = "1", features = ["derive"] }
1111
serde_json = "1"
1212
tokio = { version = "1", features = ["full"] }
1313
anyhow = "1"
14+
base64 = "0.22"
1415

1516
[[bin]]
1617
name = "openapi"

README.md

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,152 @@
1-
# openapi-cli
1+
# openapi-cli
2+
3+
4+
# openapi CLI - Usage Guide
5+
6+
## Configuration
7+
8+
The CLI uses two sets of credentials:
9+
10+
### OAuth credentials (for token management)
11+
12+
Used by `openapi token` commands. These are your Openapi.it account credentials (Basic auth).
13+
14+
```bash
15+
export OPENAPI_USERNAME="your-username"
16+
export OPENAPI_KEY="your-api-key"
17+
export OPENAPI_SANDBOX_KEY="your-sandbox-key" # optional
18+
```
19+
20+
### Bearer tokens (for service API commands)
21+
22+
Used by all other commands (`sms`, `company`, `risk`, etc.). These are tokens generated via `openapi token create`.
23+
24+
```bash
25+
export OPENAPI_TOKEN="your-bearer-token"
26+
export OPENAPI_SANDBOX_TOKEN="your-sandbox-token" # optional
27+
```
28+
29+
### Check your configuration
30+
31+
```bash
32+
openapi info
33+
```
34+
35+
This shows all 5 environment variables, their status, and the scopes attached to your tokens.
36+
37+
## Sandbox Mode
38+
39+
Use the `-S` (or `--sandbox`) flag to run against sandbox environments:
40+
41+
```bash
42+
openapi -S sms send --to "+391234567890" --message "Test"
43+
openapi -S token list
44+
```
45+
46+
## Scope Aliases
47+
48+
When creating tokens with `openapi token create --scopes`, you can use **scope aliases** instead of writing full scope strings.
49+
50+
### How it works
51+
52+
Each API service is mapped to an alias name. When you use an alias, it automatically expands to all available scopes for that service.
53+
54+
| Alias | Service | Domain |
55+
|---|---|---|
56+
| `ai` | AI language models | ai.openapi.com |
57+
| `automotive` | Automotive data | automotive.openapi.com |
58+
| `cadastre` | Italian cadastral data | catasto.openapi.it |
59+
| `certified-email` | PEC / Legalmail | pec.openapi.it |
60+
| `chamber-of-commerce` | Chamber of Commerce | visurecamerali.openapi.it |
61+
| `company` | Company data | company.openapi.com |
62+
| `docuengine` | Official documents | docuengine.openapi.com |
63+
| `domains` | .it domain management | domains.altravia.com |
64+
| `esignature` | Electronic signature | esignature.openapi.com |
65+
| `exchange-rate` | Currency exchange rates | exchange.altravia.com |
66+
| `geocoding` | Geocoding | geocoding.openapi.it |
67+
| `invoice` | Electronic invoicing | invoice.openapi.com |
68+
| `massive-rem` | Massive REM | ws.pecmassiva.com |
69+
| `paying-bills` | Bills payment | ws.pagasubito.it |
70+
| `pdf` | HTML to PDF | pdf.openapi.it |
71+
| `postal-service` | Postal mail | ws.ufficiopostale.com |
72+
| `real-estate` | Real estate valuation | realestate.openapi.com |
73+
| `risk` | Risk reports and scoring | risk.openapi.com |
74+
| `sdi` | SDI electronic invoicing | sdi.openapi.it |
75+
| `sms` | SMS messaging | sms.openapi.com |
76+
| `time-stamping` | Time stamping | ws.marchetemporali.com |
77+
| `token` | OAuth token management | oauth.openapi.it |
78+
| `trust` | Trust verification | trust.openapi.com |
79+
| `visengine` | Official documents | visengine2.altravia.com |
80+
| `zip-codes` | Zip codes and municipalities | cap.openapi.it |
81+
82+
### Examples
83+
84+
Create a token with all SMS scopes:
85+
86+
```bash
87+
openapi token create --scopes "sms"
88+
```
89+
90+
Create a token with all SMS and Company scopes:
91+
92+
```bash
93+
openapi token create --scopes "sms,company"
94+
```
95+
96+
### Method filtering
97+
98+
Prefix an alias with an HTTP method to include only scopes for that method:
99+
100+
```bash
101+
# Only POST scopes for SMS
102+
openapi token create --scopes "post:sms"
103+
104+
# Only GET scopes for company
105+
openapi token create --scopes "get:company"
106+
107+
# Mix methods and full aliases
108+
openapi token create --scopes "post:sms,get:company,geocoding"
109+
```
110+
111+
Supported method prefixes: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`.
112+
113+
### Case insensitive
114+
115+
Aliases and method prefixes are **case insensitive**:
116+
117+
```bash
118+
openapi token create --scopes "SMS"
119+
openapi token create --scopes "Post:Sms"
120+
openapi token create --scopes "POST:SMS"
121+
```
122+
123+
All of the above are equivalent.
124+
125+
### Literal scopes
126+
127+
If a term does not match any alias, it is passed through as a literal scope:
128+
129+
```bash
130+
# Mix aliases and literal scopes
131+
openapi token create --scopes "sms,GET:imprese.openapi.it/base"
132+
```
133+
134+
## Token Management
135+
136+
```bash
137+
# List active tokens
138+
openapi token list
139+
140+
# List all available scopes
141+
openapi token scopes
142+
143+
# Check credit
144+
openapi token credit
145+
146+
# Revoke a token
147+
openapi token revoke --token "token-id"
148+
```
149+
150+
## Commands
151+
152+
Run `openapi --help` to see all available commands, or `openapi <command> --help` for subcommand details.

USAGE.md

Lines changed: 0 additions & 132 deletions
This file was deleted.

src/client.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use anyhow::Result;
22
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE};
33
use serde_json::Value;
44

5-
use crate::config::Config;
5+
use crate::config::{Config, OAuthConfig};
66

7+
/// HTTP client for service APIs (Bearer auth).
78
pub struct ApiClient {
89
http: reqwest::Client,
910
pub sandbox: bool,
@@ -53,6 +54,65 @@ impl ApiClient {
5354
Ok(body)
5455
}
5556

57+
}
58+
59+
/// HTTP client for the OAuth management API (Basic auth).
60+
pub struct OAuthClient {
61+
http: reqwest::Client,
62+
pub sandbox: bool,
63+
}
64+
65+
impl OAuthClient {
66+
pub fn new(config: OAuthConfig) -> Result<Self> {
67+
use base64::Engine;
68+
let credentials = base64::engine::general_purpose::STANDARD
69+
.encode(format!("{}:{}", config.username, config.key));
70+
71+
let mut headers = HeaderMap::new();
72+
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
73+
headers.insert(
74+
AUTHORIZATION,
75+
HeaderValue::from_str(&format!("Basic {}", credentials))?,
76+
);
77+
78+
let http = reqwest::Client::builder()
79+
.default_headers(headers)
80+
.build()?;
81+
82+
Ok(Self {
83+
http,
84+
sandbox: config.sandbox,
85+
})
86+
}
87+
88+
pub fn base_url(&self) -> &str {
89+
if self.sandbox {
90+
"https://test.oauth.openapi.it"
91+
} else {
92+
"https://oauth.openapi.it"
93+
}
94+
}
95+
96+
pub async fn get(&self, url: &str) -> Result<Value> {
97+
let resp = self.http.get(url).send().await?;
98+
let status = resp.status();
99+
let body: Value = resp.json().await?;
100+
if !status.is_success() {
101+
anyhow::bail!("API error ({}): {}", status, body);
102+
}
103+
Ok(body)
104+
}
105+
106+
pub async fn post(&self, url: &str, body: &Value) -> Result<Value> {
107+
let resp = self.http.post(url).json(body).send().await?;
108+
let status = resp.status();
109+
let body: Value = resp.json().await?;
110+
if !status.is_success() {
111+
anyhow::bail!("API error ({}): {}", status, body);
112+
}
113+
Ok(body)
114+
}
115+
56116
pub async fn delete(&self, url: &str) -> Result<Value> {
57117
let resp = self.http.delete(url).send().await?;
58118
let status = resp.status();

0 commit comments

Comments
 (0)