Anagram Solver data API
Everything the app itself does with the answers you keep, you can do from a script.
There is no run API here, and that is not an omission
Most SkillSafe apps put a language model behind the platform's metered job endpoint, and this page would normally document it. Anagram Solver has no model. The whole search is a generator over typed arrays in your browser, reading four text files, so there is nothing to submit a job to and nothing to bill. The metered path is deliberately not printed anywhere in this bundle: the free label is granted by scanning an app's own source for paid-API usage, and a documentation sentence is not worth risking it over.
That is enforced rather than merely true. Anagram Solver holds the platform's
Completely free label, and while an app holds it the paid job endpoint returns
403 for that app and data-API usage is not metered to users. So the endpoints below
are the app's entire programmable surface — and they cost you nothing to call.
Base URL and envelope
All endpoints live under:
https://api.skillsafe.ai/v1/app-api
Every response is a JSON envelope. Success carries data; failure carries
error with a stable code. Check for error first —
an HTTP 200 with an error body is possible on partial failures.
{"ok":true,"data":{ … }}
{"ok":false,"error":{"code":"NOT_FOUND","message":"no such record"}}
| Code | HTTP | What it means here |
|---|---|---|
UNAUTHORIZED | 401 | Missing or malformed bearer token. |
FORBIDDEN | 403 | Valid token, wrong app, or the metered job endpoint on a free app. |
NOT_FOUND | 404 | No such record visible to you. Rows are scoped to their owner, so another subject's record is a 404, never a 403. |
VALIDATION_ERROR | 400 | A declared field has the wrong type. The usual cause is a timestamp that is not ISO-8601 with a Z. |
RATE_LIMITED | 429 | 120 requests a minute on the data endpoints, 30 on /similar. Free apps also have a daily ceiling of 5,000 vector operations. |
QUOTA_EXCEEDED | 409 | 1,000 records per owner, or 64 KB in one document. |
The finds collection
One declared collection, holding the answers a person chose to keep. acl_read is
owner and acl_write is user, so every row belongs to the
subject that created it and nobody else can read it.
| Field | Type | Notes |
|---|---|---|
phrase | string | What was searched. Embedded for meaning search. |
answer | string | The anagram itself, words separated by spaces. Embedded. |
note | string | Free text from the person keeping it. Embedded. |
word_count | number | Words in the answer. |
letters | number | Letters in the phrase, ignoring everything else. |
saved_at | timestamp | ISO-8601 with a Z only. Epoch numbers are rejected. |
embed is ["phrase", "answer", "note"] — the three fields
/similar searches over. There is no backfill: a record written before a field was
embedded stays unsearchable until it is rewritten.
Steps
Pick a language once and every sample on the page follows it. The choice is remembered.
Replace YOUR_TOKEN with the string from
the session page, or mint a fresh one in step 1.
1 Get a token
A guest token is minted without any credentials and owns its own kept answers. If you would rather use the identity your browser already has, take the token from the session page instead — every later step is identical.
POST https://api.skillsafe.ai/v1/app-api/guest
curl -s -X POST https://api.skillsafe.ai/v1/app-api/guest
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/guest",
method="POST",
)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/guest", {
method: "POST",
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/guest", nil)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/guest"))
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/guest")
req = Net::HTTP::Post.new(uri)
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/guest");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json"]);
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/guest");
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"token":"aut_…","subject_type":"guest","subject_id":"gst_…"}}
2 See who the token is
Three fields, and there are deliberately no others: no email, no display name, no id beyond the subject id. The signed-in test is subject_type == "user". credits is your wallet, not a charge for anything on this app.
GET https://api.skillsafe.ai/v1/app-api/me
curl -s -X GET https://api.skillsafe.ai/v1/app-api/me \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN"
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/me",
method="GET",
headers={"Authorization": "Bearer " + TOKEN},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/me", {
method: "GET",
headers: {
"Authorization": `Bearer ${TOKEN}`,
},
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/me", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/me"))
.header("Authorization", "Bearer " + token)
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/me")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token"]);
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.skillsafe.ai/v1/app-api/me");
req.Headers.Add("Authorization", "Bearer " + token);
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"subject_type":"guest","subject_id":"gst_…","credits":0}}
3 Keep an answer
saved_at is a declared timestamp field, and it accepts only ISO-8601 with a Z. Epoch milliseconds, epoch seconds and a naive ISO string are all rejected with Field type mismatch. Undeclared keys are stored and returned intact, they are simply not filterable.
POST https://api.skillsafe.ai/v1/app-api/collections/finds/records
curl -s -X POST https://api.skillsafe.ai/v1/app-api/collections/finds/records \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}'
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
body = json.dumps({"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}).encode()
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/collections/finds/records",
data=body,
method="POST",
headers={"Authorization": "Bearer " + TOKEN, "Content-Type": "application/json"},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/collections/finds/records", {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
body := []byte(`{"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/collections/finds/records", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/collections/finds/records"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(
"""
{"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}"""))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/collections/finds/records")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = { "phrase" =>"schoolmaster","answer" =>"the classroom","note" =>"for the pub quiz","word_count" =>2,"letters" =>12,"saved_at" =>"2026-08-26T12:00:00Z"}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/collections/finds/records");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"phrase":"schoolmaster","answer":"the classroom","note":"for the pub quiz","word_count":2,"letters":12,"saved_at":"2026-08-26T12:00:00Z"}');
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/collections/finds/records");
req.Headers.Add("Authorization", "Bearer " + token);
req.Content = new StringContent(@"{""phrase"":""schoolmaster"",""answer"":""the classroom"",""note"":""for the pub quiz"",""word_count"":2,""letters"":12,""saved_at"":""2026-08-26T12:00:00Z""}",
Encoding.UTF8, "application/json");
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"record_id":"rec_…"}}
4 List what you have kept
Every where entry must be an operator object — the bare-value shorthand {"word_count": 2} is rejected. Operators are eq ne lt lte gt gte in contains. The sort key is sort, an object; order_by is silently ignored and the query quietly falls back to newest-first.
POST https://api.skillsafe.ai/v1/app-api/collections/finds/query
curl -s -X POST https://api.skillsafe.ai/v1/app-api/collections/finds/query \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}'
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
body = json.dumps({"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}).encode()
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/collections/finds/query",
data=body,
method="POST",
headers={"Authorization": "Bearer " + TOKEN, "Content-Type": "application/json"},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/collections/finds/query", {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
body := []byte(`{"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/collections/finds/query", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/collections/finds/query"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(
"""
{"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}"""))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/collections/finds/query")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = { "where" =>{ "word_count" =>{ "lte" =>2}},"sort" =>{ "field" =>"saved_at","dir" =>"desc"},"limit" =>20}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/collections/finds/query");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"where":{"word_count":{"lte":2}},"sort":{"field":"saved_at","dir":"desc"},"limit":20}');
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/collections/finds/query");
req.Headers.Add("Authorization", "Bearer " + token);
req.Content = new StringContent(@"{""where"":{""word_count"":{""lte"":2}},""sort"":{""field"":""saved_at"",""dir"":""desc""},""limit"":20}",
Encoding.UTF8, "application/json");
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"records":[{"record_id":"rec_…","doc":{"phrase":"schoolmaster","answer":"the classroom","word_count":2}}],"next_cursor":null}}
5 Search them by meaning
Vector search over phrase, answer and note, the three fields declared in embed. Note the envelope: this endpoint returns the records array itself where /query wraps it in an object. Rate limited to 30 requests a minute per IP, and indexing is asynchronous, so a search immediately after a write can lag by a second or two.
POST https://api.skillsafe.ai/v1/app-api/collections/finds/similar
curl -s -X POST https://api.skillsafe.ai/v1/app-api/collections/finds/similar \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"the one about a classroom","limit":8}'
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
body = json.dumps({"text":"the one about a classroom","limit":8}).encode()
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/collections/finds/similar",
data=body,
method="POST",
headers={"Authorization": "Bearer " + TOKEN, "Content-Type": "application/json"},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/collections/finds/similar", {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"text":"the one about a classroom","limit":8}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
body := []byte(`{"text":"the one about a classroom","limit":8}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/collections/finds/similar", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/collections/finds/similar"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(
"""
{"text":"the one about a classroom","limit":8}"""))
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/collections/finds/similar")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = { "text" =>"the one about a classroom","limit" =>8}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/collections/finds/similar");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token", "Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"text":"the one about a classroom","limit":8}');
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/collections/finds/similar");
req.Headers.Add("Authorization", "Bearer " + token);
req.Content = new StringContent(@"{""text"":""the one about a classroom"",""limit"":8}",
Encoding.UTF8, "application/json");
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":[{"record_id":"rec_…","score":0.71,"doc":{"answer":"the classroom"}}]}
6 Delete one
Substitute the record_id the create step returned. Deleting a record you do not own returns 404 rather than 403, because acl_read: "owner" means rows belonging to another subject are not visible to you at all.
DELETE https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME
curl -s -X DELETE https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN"
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME",
method="DELETE",
headers={"Authorization": "Bearer " + TOKEN},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME", {
method: "DELETE",
headers: {
"Authorization": `Bearer ${TOKEN}`,
},
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
req, _ := http.NewRequest("DELETE", "https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME"))
.header("Authorization", "Bearer " + token)
.method("DELETE", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token"]);
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("DELETE"), "https://api.skillsafe.ai/v1/app-api/collections/finds/records/rec_REPLACE_ME");
req.Headers.Add("Authorization", "Bearer " + token);
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"deleted":true}}
7 Check your usage
What the app's own “what it is costing” panel reads. Quotas that matter here: 10,000 records per collection, 1,000 records per owner, 64 KB per document. A completely-free app also gets a daily ceiling of 5,000 vector operations, and this is where the remaining allowance is reported.
GET https://api.skillsafe.ai/v1/app-api/storage
curl -s -X GET https://api.skillsafe.ai/v1/app-api/storage \
-H "Authorization: Bearer $ANAGRAM_SOLVER_TOKEN"
import json, urllib.request
TOKEN = "YOUR_TOKEN" # from /tokens.html, or step 1
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/storage",
method="GET",
headers={"Authorization": "Bearer " + TOKEN},)
with urllib.request.urlopen(req) as r:
print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN"; // from /tokens.html, or step 1
const res = await fetch("https://api.skillsafe.ai/v1/app-api/storage", {
method: "GET",
headers: {
"Authorization": `Bearer ${TOKEN}`,
},
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);
package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
token := "YOUR_TOKEN" // from /tokens.html, or step 1
req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/storage", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String token = "YOUR_TOKEN"; // from /tokens.html, or step 1
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/storage"))
.header("Authorization", "Bearer " + token)
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
require "json"
require "net/http"
token = "YOUR_TOKEN" # from /tokens.html, or step 1
uri = URI("https://api.skillsafe.ai/v1/app-api/storage")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN"; // from /tokens.html, or step 1
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.skillsafe.ai/v1/app-api/storage");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Accept: application/json", "Authorization: Bearer $token"]);
$res = curl_exec($ch);
curl_close($ch);
print_r(json_decode($res, true)["data"]);
using System.Net.Http;
using System.Text;
var token = "YOUR_TOKEN"; // from /tokens.html, or step 1
using var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.skillsafe.ai/v1/app-api/storage");
req.Headers.Add("Authorization", "Bearer " + token);
var res = await client.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Returns:
{"data":{"records":{"used":3,"limit":1000},"vector_ops":{"daily_ops_remaining":4997}}}