@unavatar/core 3.14.0 → 3.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +171 -118
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,66 +1,20 @@
1
1
  ![logo](https://unavatar.io/api/og ':id=banner')
2
2
 
3
- - [Table of Contents](#table-of-contents)
4
- - [Introduction](#introduction)
5
- - [Quick start](#quick-start)
6
- - [Query parameters](#query-parameters)
7
- - [TTL](#ttl)
8
- - [Fallback](#fallback)
9
- - [JSON](#json)
10
- - [Pricing](#pricing)
11
- - [Providers](#providers)
12
- - [Apple Music](#apple-music)
13
- - [Behance](#behance)
14
- - [Bluesky](#bluesky)
15
- - [DeviantArt](#deviantart)
16
- - [Discord](#discord)
17
- - [Dribbble](#dribbble)
18
- - [DuckDuckGo](#duckduckgo)
19
- - [GitHub](#github)
20
- - [GitLab](#gitlab)
21
- - [LinkedIn](#linkedin)
22
- - [Google](#google)
23
- - [Instagram](#instagram)
24
- - [Ko-fi](#ko-fi)
25
- - [Medium](#medium)
26
- - [Microlink](#microlink)
27
- - [Mastodon](#mastodon)
28
- - [OnlyFans](#onlyfans)
29
- - [OpenStreetMap](#openstreetmap)
30
- - [Patreon](#patreon)
31
- - [Printables](#printables)
32
- - [Reddit](#reddit)
33
- - [Snapchat](#snapchat)
34
- - [SoundCloud](#soundcloud)
35
- - [Spotify](#spotify)
36
- - [Substack](#substack)
37
- - [Telegram](#telegram)
38
- - [Threads](#threads)
39
- - [TikTok](#tiktok)
40
- - [Twitch](#twitch)
41
- - [Vimeo](#vimeo)
42
- - [WhatsApp](#whatsapp)
43
- - [YouTube](#youtube)
44
- - [Response Format](#response-format)
45
- - [Response Headers](#response-headers)
46
-
47
- ---
48
-
49
3
  ## Table of Contents
50
4
 
51
5
  - [Introduction](#introduction)
52
6
  - [Quick start](#quick-start)
7
+ - [Authentication](#authentication)
8
+ - [Pricing](#pricing)
9
+ - [Cache](#cache)
53
10
  - [Query parameters](#query-parameters)
54
11
  - [TTL](#ttl)
55
12
  - [Fallback](#fallback)
56
13
  - [JSON](#json)
57
- - [Pricing](#pricing)
58
14
  - [Providers](#providers)
59
15
  - [Apple Music](#apple-music)
60
- - [Behance](#behance)
61
16
  - [Bluesky](#bluesky)
62
17
  - [DeviantArt](#deviantart)
63
- - [Discord](#discord)
64
18
  - [Dribbble](#dribbble)
65
19
  - [DuckDuckGo](#duckduckgo)
66
20
  - [GitHub](#github)
@@ -77,12 +31,10 @@
77
31
  - [Patreon](#patreon)
78
32
  - [Printables](#printables)
79
33
  - [Reddit](#reddit)
80
- - [Snapchat](#snapchat)
81
34
  - [SoundCloud](#soundcloud)
82
35
  - [Spotify](#spotify)
83
36
  - [Substack](#substack)
84
37
  - [Telegram](#telegram)
85
- - [Threads](#threads)
86
38
  - [TikTok](#tiktok)
87
39
  - [Twitch](#twitch)
88
40
  - [Vimeo](#vimeo)
@@ -117,6 +69,161 @@ The service is exposed in **unavatar.io** via provider endpoints:
117
69
 
118
70
  Use the `/:provider/:key` format for all lookups. You can read more about available providers in [providers](https://unavatar.io/docs#providers).
119
71
 
72
+ ## Authentication
73
+
74
+ The anonymous requests works without authentication. They are limited to 25 requests/day per IP address.
75
+
76
+ For [PRO](https://unavatar.io/checkout) users, the requests must include the API key as the `x-api-key` request header:
77
+
78
+ ``` bash
79
+ curl -H "x-api-key: YOUR_API_KEY" "https://[unavatar.io/github/kikobeats"](https://unavatar.io/github/kikobeats")
80
+ ```
81
+
82
+ ``` javascript
83
+ await fetch('https://[unavatar.io/github/kikobeats',](https://unavatar.io/github/kikobeats',) {
84
+ headers: {
85
+ 'x-api-key': process.env.UNAVATAR_API_KEY
86
+ }
87
+ })
88
+ ```
89
+
90
+ ``` python
91
+ import os
92
+ import requests
93
+
94
+ response = requests.get(
95
+ 'https://[unavatar.io/github/kikobeats',](https://unavatar.io/github/kikobeats',)
96
+ headers={'x-api-key': os.environ['UNAVATAR_API_KEY']}
97
+ )
98
+ ```
99
+
100
+ ``` golang
101
+ package main
102
+
103
+ import (
104
+ "net/http"
105
+ "os"
106
+ )
107
+
108
+ func main() {
109
+ req, _ := http.NewRequest("GET", "https://[unavatar.io/github/kikobeats",](https://unavatar.io/github/kikobeats",) nil)
110
+ req.Header.Set("x-api-key", os.Getenv("UNAVATAR_API_KEY"))
111
+
112
+ resp, _ := http.DefaultClient.Do(req)
113
+ defer resp.Body.Close()
114
+ }
115
+ ```
116
+
117
+ ``` ruby
118
+ require 'net/http'
119
+ require 'uri'
120
+
121
+ uri = URI('https://[unavatar.io/github/kikobeats')](https://unavatar.io/github/kikobeats'))
122
+ request = Net::HTTP::Get.new(uri)
123
+ request['x-api-key'] = ENV['UNAVATAR_API_KEY']
124
+
125
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
126
+ http.request(request)
127
+ end
128
+ ```
129
+
130
+ ``` php
131
+ $ch = curl_init('https://[unavatar.io/github/kikobeats');](https://unavatar.io/github/kikobeats');)
132
+
133
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
134
+ 'x-api-key: ' . getenv('UNAVATAR_API_KEY'),
135
+ ]);
136
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
137
+
138
+ $response = curl_exec($ch);
139
+ curl_close($ch);
140
+ ```
141
+
142
+ If the API key is invalid, the service returns `401` with code `EAPIKEY`.
143
+
144
+ Rate limit status can be verified using these response headers:
145
+
146
+ | Header | Description |
147
+ | ------------------------ | -------------------------------------------------------------- |
148
+ | `x-rate-limit-limit` | Maximum anonymous requests allowed in the current daily window |
149
+ | `x-rate-limit-remaining` | Requests remaining in the current window |
150
+ | `x-rate-limit-reset` | UTC epoch seconds when the current window resets |
151
+
152
+ ``` bash
153
+ $ curl -I https://[unavatar.io/github/kikobeats](https://unavatar.io/github/kikobeats)
154
+
155
+ x-rate-limit-limit: 25
156
+ x-rate-limit-remaining: 24
157
+ x-rate-limit-reset: 1744243200
158
+ ```
159
+
160
+ ## Pricing
161
+
162
+ Unavatar pricing is simple: you can start on the anonymous free tier, then authenticate with `x-api-key` to get additional included usage and metered billing for higher volume.
163
+
164
+ | Scenario | Included free usage | Billing |
165
+ | -------------------------------------------- | ---------------------- | -------------------------------- |
166
+ | Anonymous (no API key) | 25 requests/day per IP | Free |
167
+ | Authenticated origin requests (`x-api-key`) | 50 origin requests/day | Metered monthly after free quota |
168
+ | Proxy requests (`datacenter`, `residential`) | None | Always metered |
169
+
170
+ For higher usage, the **[PRO](https://unavatar.io/checkout)** plan is usage-based billing that includes the 50 free daily origin requests, metered overage, and custom TTL.
171
+
172
+ Every request has a cost in tokens (**\$0.005 per token**) based on the proxy tier needed to resolve the avatar:
173
+
174
+ | Proxy tier | Tokens | Cost |
175
+ | ----------- | :----: | :-----: |
176
+ | Origin | 1 | \$0.005 |
177
+ | Datacenter | +2 | \$0.015 |
178
+ | Residential | +4 | \$0.025 |
179
+
180
+ The proxy tier used is returned in the `x-proxy-tier` response header, and the total cost in the `x-unavatar-cost` header.
181
+
182
+ ``` bash
183
+ $ curl -I -H "x-api-key: YOUR_API_KEY" https://[unavatar.io/instagram/kikobeats](https://unavatar.io/instagram/kikobeats)
184
+
185
+ x-pricing-tier: pro
186
+ x-proxy-tier: origin
187
+ x-unavatar-cost: 1
188
+ ```
189
+
190
+ To upgrade, visit [unavatar.io/checkout](https://unavatar.io/checkout). After completing the payment, you'll receive an API key.
191
+
192
+ ## Cache
193
+
194
+ Unavatar caches avatar lookups to make repeated requests fast and stable:
195
+
196
+ - The first request for a resource fetches the avatar from upstream and stores it in cache
197
+ - Following requests are served from cache until the [TTL](https://unavatar.io/docs#ttl) expires.
198
+
199
+ For example, if you set `ttl=1h`, the cache behavior looks like this:
200
+
201
+ | Time | Request | Cache status | Plan impact |
202
+ | ----- | ----------------------- | ----------------------------------- | -------------------------- |
203
+ | 10:00 | `GET /github/kikobeats` | MISS (fetched from upstream) | Counts as 1 origin request |
204
+ | 10:05 | `GET /github/kikobeats` | HIT (served from cache) | No usage consumed, no cost |
205
+ | 10:40 | `GET /github/kikobeats` | HIT (served from cache) | No usage consumed, no cost |
206
+ | 11:02 | `GET /github/kikobeats` | MISS (TTL expired, cache refreshed) | Counts as 1 origin request |
207
+ | 11:10 | `GET /github/kikobeats` | HIT (served from cache) | No usage consumed, no cost |
208
+
209
+ To check the cache status in real requests, inspect these response headers:
210
+
211
+ | Header | What to look for |
212
+ | ---------------- | --------------------------------------------------------------------------------------- |
213
+ | `x-cache-status` | `HIT` means served from cache. `MISS` means fetched/refreshed from upstream. |
214
+ | `cache-control` | Shows cache policy and effective TTL (for example `public, max-age=3600` for `ttl=1h`). |
215
+
216
+ ``` bash
217
+ $ curl -I -H "x-api-key: YOUR_API_KEY" "https://[unavatar.io/github/kikobeats?ttl=1h"](https://unavatar.io/github/kikobeats?ttl=1h")
218
+
219
+ cache-control: public, max-age=3600
220
+ x-cache-status: HIT
221
+ ```
222
+
223
+ The same rule applies to anonymous requests: cache hits are free and do not consume the `25 requests/day` limit.
224
+
225
+ After TTL expiration, the next request refreshes the cache and is billed/rate-limited according to the request tier (`anonymous`, `origin`, `datacenter`, or `residential`).
226
+
120
227
  ## Query parameters
121
228
 
122
229
  ### TTL
@@ -167,40 +274,6 @@ In case you want to get a JSON payload as response, just pass `json=true`:
167
274
 
168
275
  e.g., [unavatar.io/github/kikobeats?json](https://unavatar.io/github/kikobeats?json)
169
276
 
170
- ## Pricing
171
-
172
- The service is **FREE** for everyone, no registration required, with a daily rate limit of **50 requests** per IP address.
173
-
174
- For preventing abusive usage, the service has associated a daily rate limit based on requests IP address.
175
-
176
- You can verify for your rate limit state checking the following headers in the response:
177
-
178
- - `x-rate-limit-limit`: The maximum number of requests that the consumer is permitted to make per minute.
179
- - `x-rate-limit-remaining`: The number of requests remaining in the current rate limit window.
180
- - `x-rate-limit-reset`: The time at which the current rate limit window resets in UTC epoch seconds.
181
-
182
- For higher usage, the **[PRO](https://unavatar.io/checkout)** plan is a usage-based plan billed monthly that removes rate limits and unlocks custom TTL.
183
-
184
- Every request has a cost in tokens (**\$0.005 per token**) based on the proxy tier needed to resolve the avatar:
185
-
186
- | Proxy tier | Tokens | Cost |
187
- | ----------- | :----: | :-----: |
188
- | Origin | 1 | \$0.005 |
189
- | Datacenter | +2 | \$0.015 |
190
- | Residential | +4 | \$0.025 |
191
-
192
- The proxy tier used is returned in the `x-proxy-tier` response header, and the total cost in the `x-unavatar-cost` header.
193
-
194
- ``` bash
195
- $ curl -I -H "x-api-key: YOUR_API_KEY" https://[unavatar.io/instagram/kikobeats](https://unavatar.io/instagram/kikobeats)
196
-
197
- x-pricing-tier: pro
198
- x-proxy-tier: origin
199
- x-unavatar-cost: 1
200
- ```
201
-
202
- To upgrade, visit [unavatar.io/checkout](https://unavatar.io/checkout). After completing the payment, you'll receive an API key.
203
-
204
277
  ## Providers
205
278
 
206
279
  ### Apple Music
@@ -225,14 +298,6 @@ Available URI format inputs:
225
298
  - by song name: [unavatar.io/apple-music/song:harder%20better%20faster%20stronger](https://unavatar.io/apple-music/song:harder%20better%20faster%20stronger)
226
299
  - by song ID: [unavatar.io/apple-music/song:697195787](https://unavatar.io/apple-music/song:697195787)
227
300
 
228
- ### Behance
229
-
230
- Get any Behance user's profile picture by their username.
231
-
232
- Available inputs:
233
-
234
- - slug, e.g., [unavatar.io/behance/kikobeats](https://unavatar.io/behance/kikobeats)
235
-
236
301
  ### Bluesky
237
302
 
238
303
  Get any Bluesky user's profile picture by their handle. Domain-style handles are supported.
@@ -250,14 +315,6 @@ Available inputs:
250
315
 
251
316
  - slug, e.g., [unavatar.io/deviantart/spyed](https://unavatar.io/deviantart/spyed)
252
317
 
253
- ### Discord
254
-
255
- Get any Discord server icon by invite code.
256
-
257
- Available inputs:
258
-
259
- - Invite code, e.g., [unavatar.io/discord/eret](https://unavatar.io/discord/eret)
260
-
261
318
  ### Dribbble
262
319
 
263
320
  Get any Dribbble designer's profile picture by their username.
@@ -402,14 +459,6 @@ Available inputs:
402
459
 
403
460
  - slug, e.g., [unavatar.io/reddit/kikobeats](https://unavatar.io/reddit/kikobeats)
404
461
 
405
- ### Snapchat
406
-
407
- Get any Snapchat user's profile picture by their username.
408
-
409
- Available inputs:
410
-
411
- - slug, e.g., [unavatar.io/snapchat/teddysdaytoday](https://unavatar.io/snapchat/teddysdaytoday) or [unavatar.io/snapchat/@teddysdaytoday](https://unavatar.io/snapchat/@teddysdaytoday)
412
-
413
462
  ### SoundCloud
414
463
 
415
464
  Get any SoundCloud artist's profile picture by their username.
@@ -454,14 +503,6 @@ Available inputs:
454
503
 
455
504
  - slug, e.g., [unavatar.io/telegram/drsdavidsoft](https://unavatar.io/telegram/drsdavidsoft)
456
505
 
457
- ### Threads
458
-
459
- Get any Threads user's profile picture by their username.
460
-
461
- Available inputs:
462
-
463
- - slug, e.g., [unavatar.io/threads/zuck](https://unavatar.io/threads/zuck) or [unavatar.io/threads/@zuck](https://unavatar.io/threads/@zuck)
464
-
465
506
  ### TikTok
466
507
 
467
508
  Get any TikTok user's profile picture by their username. No authentication or API tokens needed — just pass the username.
@@ -555,6 +596,18 @@ These headers help you understand pricing, limits, and request diagnostics.
555
596
  | `x-rate-limit-reset` | UTC epoch seconds when window resets (free tier only) |
556
597
  | `retry-after` | Seconds until rate limit resets (only on 429 responses) |
557
598
 
599
+ ``` bash
600
+ $ curl -I -H "x-api-key: YOUR_API_KEY" https://[unavatar.io/github/kikobeats](https://unavatar.io/github/kikobeats)
601
+
602
+ x-pricing-tier: pro
603
+ x-timestamp: 1744209600
604
+ x-unavatar-cost: 1
605
+ x-proxy-tier: origin
606
+ x-rate-limit-limit: 50
607
+ x-rate-limit-remaining: 49
608
+ x-rate-limit-reset: 1744243200
609
+ ```
610
+
558
611
  Expected errors are known operational cases returned with stable codes.
559
612
 
560
613
  - **Client-side issues** return `status: "fail"` (HTTP `4xx`).
@@ -583,7 +636,7 @@ Expected errors are known operational cases returned with stable codes.
583
636
  | 409 | `EAPIKEYEXISTS` | Custom API key already exists |
584
637
  | 409 | `EAPIKEYLABELEXISTS` | API key label already exists |
585
638
  | 409 | `EAPIKEYMIN` | Attempt to remove last remaining key |
586
- | 429 | `ERATE` | Free-tier daily rate limit exceeded |
639
+ | 429 | `ERATE` | Anonymous daily rate limit exceeded |
587
640
  | 500 | `ECHECKOUT` | Stripe checkout session creation failed |
588
641
  | 500 | `EAPIKEYFAILED` | API key retrieval after checkout failed |
589
642
  | 500 | `EINTERNAL` | Unexpected internal server failure |
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@unavatar/core",
3
3
  "description": "Get unified user avatar from social networks, including Instagram, SoundCloud, Telegram, Twitter, YouTube & more.",
4
4
  "homepage": "https://unavatar.io",
5
- "version": "3.14.0",
5
+ "version": "3.14.2",
6
6
  "main": "src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js",