Product

How it works Widgets Compare HAPI score

Who it's for

Professionals Companies Services

More

Developers Pricing Journal
Claim your pageSign in

API reference

The Moat API uses plain HTTPS requests with form-encoded bodies and returns JSON. Profiles, companies and services each have their own endpoints.

Base URL#

https://moat.page

Paths below are relative to this origin. Endpoints are available with or without a .php suffix.

Authentication#

MethodWhere it's usedWhat it unlocks
X-API-Key headerYour server onlyAll partner endpoints, full profiles, email and phone
X-Private-Key headerYour server, for one personThat person's full profile, including email and phone
public_key parameterBrowsers and serversPublic and full profile levels, never contact details
NoneAnywhereCard and public levels of public profiles, public directories

Responses and errors#

Every response is JSON with a boolean success. Failures add an error string and use a matching HTTP status.

{ "success": false, "error": "private_key, public_key, or email required" }
StatusMeaning
200Success. Check fields such as created or updated for what changed.
400A required field is missing or invalid.
401Missing or wrong key, or a level that needs more authentication.
403Not allowed, for example account_suspended or editing a company you didn't create.
404No profile, company or service matched.
429Rate limit reached on a public endpoint. Retry after a short wait.
500Something failed on our side. Safe to retry get-or-create and update calls.

Identifying a person#

Endpoints that act on one profile accept private_key, public_key or email, tried in that order. Prefer the private key on servers. It's the most specific and it doesn't change if the person changes their email.

Profiles#

Check for a profile

POST/profile/api/has_profileX-API-Key

Returns whether a person has a Moat page, and their keys if they do. Send one of email, public_key or private_key.

{
  "success": true,
  "has_profile": true,
  "profile_key": "7qzwrjebfpaw",
  "profile_url": "https://moat.page/profile/d/amara-okafor-7qzwrjebfpaw",
  "public_key": "c6424007df52eee0ee82483f7c464dc3",
  "private_key": "prv_..."
}

Get or create a profile

POST/profile/api/create_profileX-API-Key

Returns the existing profile matched by private key, public key or email, or creates one. Existing data is never overwritten. created tells you which happened.

FieldRequiredDescription
email or user_keyYesWho the profile belongs to
first_name, last_name, public_chat_nameNoName and display name
profile_typeNoprofessional, employer or provider
current_title, current_company, headline, aboutNoStarter content for a new page
country, state_region, city, timezoneNoLocation, with ISO 3166 country codes
skills, experience, educationNoJSON arrays, for example [{"value":"Figma","proficiency":"expert"}]
profile_flagsNoComma-separated status signal keys
site_url, site_nameWith any site fieldAdds your app to the person's connected apps
callback_site_paramRecommendedStable key for your app, used to match and remove your entry
user_update_pathFor webhooksHTTPS URL that receives events for this person
site_logo_url, site_edit_urlNoBranding and an edit link shown to the person

Update a profile

POST/profile/api/update_profileX-API-Key

Overwrites the fields you send and leaves the rest alone. Accepts the same fields as create, plus contact_phone. Returns 404 if no profile matches, so fall back to create. Returns "updated": false when nothing changed.

Connect or disconnect your app

POST/profile/api/update_site_entryX-API-Key

Adds or updates your app in the person's connected apps without touching anything else. Send remove=1 with your callback_site_param to disconnect. Removing your own entry doesn't trigger a webhook back to you.

Read a profile

GET/profile/api/widget_profile.phpNone, public_key or key
ParameterDescription
public_keyThe person's public key
levelstrip (card), public or full
viewer_keyOptional public key of the viewer, adds is_following

Rate-limited to 60 requests per minute per IP. Results sit under output.user. The widget docs list the fields in each level.

Directory

POST/profile/api/directoryX-API-Key
GET/profile/api/directoryNone

Paginated lists of complete profiles. Filter by site_name to list only people connected from your app.

ParameterDescription
searchName, headline, title, company or city
site_nameOnly profiles connected from this app
flag_slugA curated audience, such as open-to-work or need-mentor. Also available as /profile/api/directory/flag/{slug}
skill_slugPeople with a skill, such as machine-learning. Also /profile/api/directory/skill/{slug}
profile_type, industry, country, status, skillsField filters. skills must all match
page, per_page1-based page, up to 50 per page (default 20)

Companies#

GET/company/api/get_company?key=co_…None
POST/company/api/create_companyX-API-Key
POST/company/api/update_companyX-API-Key
GET/company/api/my_companies?user_key=…None
GET/company/api/directoryNone

Create needs user_key and name and returns company_key and company_url. Update is partial and needs item_key plus the creator's user_key. Anyone else gets 403. Directory filters: search, industry, company_type, company_size, page, per_page. get_company accepts level=strip|public|full.

Services#

GET/service/api/get_service?key=sv_…None
POST/service/api/create_serviceX-API-Key
POST/service/api/update_serviceX-API-Key
GET/service/api/my_services?user_key=…None
GET/service/api/directoryNone

Same shape as companies. Directory filters: search, service_type, pricing_model, delivery, page, per_page.

Follows and connections#

Follow, connection and messaging endpoints are available to approved partners and documented in the partner handbook we share when your access is set up.