Access your Falando learning data programmatically — stats, SRS reviews, vocabulary, and grammar — through a simple REST API.
The Falando Open API lets you pull your own learning data — stats, SRS review state, vocabulary, and grammar — into your own scripts, dashboards, and integrations you build. It is read-only in v1.
Requires an active Premium subscription. Create keys from Settings → API.
Base URL
https://falando.app/api/v1Every request needs an API key in the Authorization header:
Authorization: Bearer fld_your_api_key_hereKeep your key secret
The key-management endpoints (POST/GET/DELETE /api/v1/api-keys) use your logged-in browser session instead of a key — use them from the Falando web app, not from external scripts.
60 requests/minute and 2,000 requests/day per account (UTC day). Every response carries your current limit status:
| Param | Type | Description |
|---|---|---|
| RateLimit-Limit | integer | Per-minute limit. |
| RateLimit-Remaining | integer | Requests left in the current minute. |
| RateLimit-Reset | epoch seconds | When the per-minute window resets. |
| X-RateLimit-Day-Limit | integer | Per-day limit. |
| X-RateLimit-Day-Remaining | integer | Requests left today (UTC). |
| X-RateLimit-Day-Reset | epoch seconds |
Every response uses the same envelope:
Success
{
"success": true,
"data": { ... }
}Error
{
"success": false,
"error": "Human-readable message",
"code": "MACHINE_READABLE_CODE"
}Responses are sent with Cache-Control: private, no-store: they are your personal data and are never served from a shared cache. A failed query always returns an error, never partial data or invented zeros.
List endpoints (/reviews, /vocabulary, /grammar) use cursor pagination:
| Param | Type | Description |
|---|---|---|
| per_page | integer | Rows per page. Default 100, max 500. |
| page_after_id | string | Pass the previous response’s pages.next_cursor to fetch the next page. |
Response shape
{
"success": true,
"data": {
"items": [ ... ],
"pages": { "per_page": 100, "next_cursor": "abc123" },
"total_count": 8449
}
}next_cursor is null on the last page. Pass an ids filter (comma-separated, max 100–500 depending on the endpoint) to fetch a specific set of rows directly — that mode ignores the cursor and returns every match in one response.
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_METRIC / INVALID_DAYS / INVALID_FORMAT / INVALID_TZ / INVALID_TYPE / INVALID_LEVEL / INVALID_POS / INVALID_UPDATED_AFTER / INVALID_CURSOR / INVALID_IDS | A query parameter is invalid. The message lists the accepted values. Fix the request; do not retry it. |
| 401 | INVALID_API_KEY | Missing, malformed, revoked, or expired API key. |
| 403 | PLAN_REQUIRED | The key belongs to a free account, or the subscription has lapsed. |
| 404 | — | The path does not exist. |
| 429 | RATE_LIMITED | Per-minute or per-day limit exceeded. See Retry-After. |
| 500 | INTERNAL_ERROR |
Your profile, subscription, and learning preferences. Subscription fields are null when access does not come from a recurring subscription (for example lifetime access), and preferences is null until settings are first saved.
curl -H "Authorization: Bearer fld_..." https://falando.app/api/v1/user{
"success": true,
"data": {
"user": {
"id": "…", "username": "capivara42", "level": "B1", "experience": 12450,
"streak": 42, "total_study_time_seconds": 186400, "last_study_date": "2026-07-01",
"daily_quests_streak": 15, "member_since": "2025-11-02T10:00:00Z"
},
"subscription": {
"plan": "paid", "lifetime": false, "status": "active", "interval": "annual",
"current_period_end": "2027-07-01T00:00:00Z", "auto_renewing": true
},
"preferences": {
"daily_goal": 20, "weekly_goal": 100, "new_vocabulary_per_day": 10,
"new_listening_per_day": 3, "timezone": "America/Sao_Paulo", "ui_language": "en"
}
}
}How many reviews are due right now, and when the next batch becomes available.
{
"success": true,
"data": {
"reviews": { "due_now": 12, "next_review_at": null },
"upcoming": [
{ "at": "2026-07-02T18:00:00.000Z", "count": 4 },
{ "at": "2026-07-02T19:00:00.000Z", "count": 9 }
]
}
}Due times follow the same schedule as the review queue in the app, so due_now matches the count you see there. next_review_at is null whenever due_now is greater than 0 — there’s nothing to wait for. upcoming buckets the next 24 hours by UTC hour. Suspended items are excluded.
Profile totals, today's activity, mastery progress, and badge count.
| Param | Type | Description |
|---|---|---|
| tz | IANA timezone | e.g. America/Sao_Paulo. Defines "today" as the current calendar day in this timezone. Default UTC. An invalid value returns 400. |
curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/stats?tz=America/Sao_Paulo"{
"success": true,
"data": {
"profile": { "level": "B1", "experience": 12450, "streak": 42,
"total_study_time_seconds": 186400, "last_study_date": "2026-07-01", "daily_quests_streak": 15 },
"today": { "study_time_seconds": 1800, "study_time_minutes": 30, "reviews_completed": 25,
"reviews_correct": 22, "reviews_accuracy": 88, "interactions": 45, "sessions_count": 2 },
"progress": { "total_items_mastered": 340, "grammar_mastered": 45, "vocabulary_mastered": 260,
"listening_mastered": 35, "total_items_in_progress": 520 },
"srs": { "items_due_now": 12 },
"achievements": { "badges_unlocked": 18 }
}
}today.* counts sessions that started today in tz, with the same rules as . is until the first review of the day. matches the review queue in the app.
Daily aggregated values for one metric — built for time-series dashboards and daily-goal tracking tools.
| Param | Type | Description |
|---|---|---|
| metric | string | study_minutes | reviews_completed | reviews_correct | items_mastered | interactions | sessions | streak. Default study_minutes. streak returns a single datapoint for today. |
| days | integer | 1–365 calendar days, including today. Default 30. Invalid values return 400. |
| format | string | default | beeminder. Beeminder returns an array of daystamp, value, and comment objects inside the success/data envelope. |
| tz | IANA timezone | e.g. America/Sao_Paulo. Default UTC. Buckets days in this timezone — use this for daily-goal integrations, or an evening session drifts onto the next UTC day. |
Per-item spaced-repetition state — when each item is next due, review and lapse counts, and more.
| Param | Type | Description |
|---|---|---|
| type | string | grammar | vocabulary | listening. |
| ids | comma-separated | Fetch specific items by id (max 100). Ignores cursor. |
| updated_after | ISO 8601 | Only items changed since this timestamp — for incremental sync. |
| page_after_id | UUID | Cursor from the previous page. |
| per_page | integer | Default 100, max 500. |
Read-only vocabulary catalog metadata (not the full lesson content — see fair use above).
| Param | Type | Description |
|---|---|---|
| levels | comma-separated CEFR | A1,A2,B1,B2,C1,C2,EX. Default: all levels. |
| pos | string | noun | verb | adjective | adverb | preposition | conjunction | interjection | phrase | numeral | pronoun | article. |
| ids | comma-separated | Fetch specific words by id (max 500). Ignores cursor. |
| updated_after | ISO 8601 | Only rows changed since this timestamp. |
| page_after_id | string |
Grammar point metadata (title, synopsis, structure). Full lesson explanations stay in-app.
| Param | Type | Description |
|---|---|---|
| levels | comma-separated CEFR | A1,A2,B1,B2,C1,C2,EX. Default: all levels. |
| ids | comma-separated | Fetch specific points by id (max 500). Ignores cursor. |
| updated_after | ISO 8601 | Only rows changed since this timestamp. |
| page_after_id | string | Cursor from the previous page. |
| per_page | integer | Default 100, max 500. |
Every v1 response allows cross-origin requests (Access-Control-Allow-Origin: *), so you can call the API directly from a browser-based dashboard. Authentication is token-only (no cookies are read or set), so this is safe.
The rate-limit headers and Retry-After are exposed to browser code, including on error responses.
The API is versioned by URL path (/api/v1/...). New fields and new endpoints are added without notice and are safe to ignore if your client doesn't know about them yet. A breaking change (a field renamed or removed, a status code meaning changed) would ship as /api/v2, with v1 kept running.
/summary, /stats (srs.items_due_now), and /reviews (next_review) could previously report an outdated schedule for some items./datapoints: documented format=beeminder. Out-of-range days and unknown format values now return 400 instead of being clamped or ignored. The window is whole calendar days in tz, including today. Sessions count on the day they started. Study minutes are rounded once per day instead of per session. Long histories are no longer cut off at 1,000 rows. A failed query returns an error instead of partial data. You can still list and revoke keys after a subscription lapses./vocabulary items include ipa (Brazilian Portuguese IPA; null where not yet available)./stats accepts for the “today” window.| Next UTC midnight. |
Exceeding either limit returns 429 RATE_LIMITED with a Retry-After header (seconds). A request refused by the rate limit never counts against your daily quota, so a burst of 429s costs you nothing but the wait. All keys on one account share the same limits.
| Unexpected server error. Safe to retry with backoff. |
| 503 | DEPENDENCY_UNAVAILABLE | Our database is temporarily unreachable. Safe to retry with backoff. |
Branch on code, not on the message text. Surface 401 and 403 to the user so they can fix their key or subscription, honor Retry-After on 429, and retry 5xx with backoff.
/datapointsreviews_accuracynullsrs.items_due_nowcurl
curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/datapoints?metric=study_minutes&days=7&tz=America/Sao_Paulo"{
"success": true,
"data": {
"metric": "study_minutes", "days": 7,
"datapoints": [
{ "date": "2026-06-26", "value": 25 },
{ "date": "2026-06-27", "value": 40 }
]
}
}curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/datapoints?metric=study_minutes&tz=America/Sao_Paulo&format=beeminder"{
"success": true,
"data": [
{ "daystamp": "20260626", "value": 25, "comment": "Falando study minutes" },
{ "daystamp": "20260627", "value": 40, "comment": "Falando study minutes" }
]
}Values are daily totals. Replace each date’s value on refresh; do not add it again. Use a stable Beeminder request ID per goal and date. Missing days within a successful response’s window mean zero; errors do not.
Study minutes sum saved active seconds, rounded once per day. Sessions use their original start time, including later offline uploads. Refresh recent days for corrections. Days start at midnight in the selected timezone; custom Beeminder deadlines are not supported.
Session counts include started sessions. streak is a current snapshot. items_mastered groups currently mastered progress rows by their latest update. Neither snapshot metric is an additive activity history.
curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/reviews?type=vocabulary&per_page=50"{
"success": true,
"data": {
"items": [{
"id": "…", "type": "vocabulary", "vocabulary_id": "casa-de-praia", "grammar_point_id": null,
"grammar_exercise_id": null, "listening_id": null, "interval": 6, "ease_factor": 2.5,
"repetitions": 4, "lapses": 0, "next_review": "2026-07-05T09:00:00Z",
"last_review": "2026-06-29T09:00:00Z", "is_suspended": false,
"created_at": "2026-01-10T12:00:00Z", "updated_at": "2026-06-29T09:00:00Z"
}],
"pages": { "per_page": 50, "next_cursor": null },
"total_count": 1
}
}next_review is when the item is next due in the app’s review queue. interval and ease_factor come from the older SM-2 schedule and are kept for compatibility; they do not decide when an item is due. Suspended items are included; filter on is_suspended.
| Cursor from the previous page. |
| per_page | integer | Default 100, max 500. |
curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/vocabulary?levels=A1&pos=verb&per_page=20"{
"success": true,
"data": {
"items": [{
"id": "falar", "level": "A1", "portuguese": "falar", "english": "to speak / to talk",
"pronunciation": "fah-LAHR", "ipa": "fa.ˈla(ʁ)", "part_of_speech": "verb", "gender": null, "frequency": "very_high",
"is_top_1000": true, "tags": ["core"], "regions": [],
"created_at": "2025-09-01T00:00:00Z", "updated_at": "2025-09-01T00:00:00Z"
}],
"pages": { "per_page": 20, "next_cursor": "gostar" },
"total_count": 8449
}
}curl -H "Authorization: Bearer fld_..." \
"https://falando.app/api/v1/grammar?levels=A1,A2"{
"success": true,
"data": {
"items": [{
"id": "present-tense-ar-verbs", "title": "Present Tense: -AR Verbs",
"short_title": "-AR present tense", "synopsis": "Conjugating regular -ar verbs in the present.",
"structure": "subject + verb stem + ending (-o, -a, -amos, -am)", "cefr": "A1", "lesson": "1.2",
"created_at": "2025-08-01T00:00:00Z", "updated_at": "2026-02-14T00:00:00Z"
}],
"pages": { "per_page": 100, "next_cursor": null },
"total_count": 178
}
}tz/user, /summary, /reviews, /vocabulary, and /grammar. /stats and /datapoints carry over unchanged from the private beta.