Developers

REST API

Programmatic access to your NapMap account — create recommendations from your CMS, attach links to existing articles, pull earnings into your analytics, all over HTTPS with bearer-token auth.

Authentication

Every endpoint expects a bearer token in the Authorization header. Tokens are managed at /profile/tokens — you assign scopes when creating one and copy the value once (we only store its SHA-256 hash).

Authorization: Bearer your_token_here

Tokens carry one or more scopes:

  • read-links — list and read your short links
  • write-links — create and delete links
  • read-articles — list and read your articles
  • write-articles — create and update articles
  • read-earnings — query earnings summary and daily breakdown
  • read-clicks — read recent click records

Base URL

https://napmap.net/api/v1

Rate limits

Two layers:

  • IP-based outer ring: 300 requests / minute / IP — catches unauthenticated probing and token stuffing.
  • Per-token bucket: 60 requests / minute / token by default (admin-configurable). Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; 429s include Retry-After.

Endpoints

GET /me

Returns the account that owns the bearer token. No scope required.

curl -H "Authorization: Bearer $TOKEN" \
     https://napmap.net/api/v1/me

Articles

GET /articles — list your articles (paginated, per_page 1–100). Requires read-articles.

GET /articles/{id} — fetch one. Requires read-articles.

POST /articles — create a new article. Requires write-articles.

curl -X POST https://napmap.net/api/v1/articles \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "category_id": 1,
    "title": "5 tools I actually used this quarter",
    "excerpt": "What survived the cull and why.",
    "content": "## The shortlist\n\nThree calendars and two notes apps walked in. One came out…",
    "language": "en",
    "publish": true
  }'

Body must be at least articles.min_content_length chars (default 200). Articles run through duplicate detection (SimHash) against your other articles — near-duplicates return 422 with error: "duplicate" and the closest match.

PATCH /articles/{id} — partial update. Same payload fields are accepted (all optional). Requires write-articles.


Links

GET /links — list (paginated). Requires read-links.

GET /links/{id} — fetch one. Requires read-links.

POST /links — create a link. Requires write-links.

Two modes:

  1. Standalone — pass destination_url only. The link is created without an article attached; readers hitting the short URL see a fallback.
  2. Attach to existing article — pass article_id of one of your articles. The link inherits the article's title + category. Each article can serve up to 20 links (cap).
curl -X POST https://napmap.net/api/v1/links \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destination_url": "https://example.com/tool-x",
    "article_id": 42
  }'

Response includes the short URL ready to share:

{
  "data": { "id": 1234, "short_code": "aBc12", "...": "..." },
  "short_url": "https://napmap.net/aBc12",
  "links_on_article": 3,
  "cap": 20
}

DELETE /links/{id} — soft delete. Requires write-links.


Earnings

GET /earnings/summary — totals (balance / pending / lifetime). Requires read-earnings.

GET /earnings/daily — last 30 days as [{date, valid_clicks, earned}]. Requires read-earnings.


Clicks

GET /clicks — recent click records (paginated). Read-only. Requires read-clicks.


Errors

All error responses use JSON shape { "error": "code", "message": "..." } with the relevant HTTP status:

  • 401 unauthorized — missing or invalid token, or token expired
  • 403 forbidden — token missing the scope needed for this endpoint
  • 404 not_found — resource doesn't exist or isn't owned by this account (we don't leak existence)
  • 422 — validation failure (standard Laravel { message, errors } shape) or domain-specific code: duplicate, blocked, cap_reached
  • 429 rate_limited — back off and retry after Retry-After seconds

Versioning

We commit to /api/v1/* being backwards-compatible. Breaking changes will land at /api/v2/* with a deprecation window announced at least 90 days in advance.

Questions?

Email [email protected].

We use cookies

Essential cookies keep the site working. With your permission we'd also use analytics + ads cookies to understand readership and support our creators — you can change this anytime. Privacy policy.