{"openapi":"3.1.0","info":{"title":"Praecise account: the shared services","version":"0.1.0","summary":"Domains, mailboxes and service tokens of one Praecise account.","description":"Account-level facts every product needs and none should learn to do itself. A request acts as exactly one account: the one a service token was issued for, or the one signed in. Signing people in is OpenID Connect and is described by the metadata at /.well-known/openid-configuration and by the guides."},"servers":[{"url":"https://accounts.praecise.com"}],"tags":[{"name":"Account","description":"Who a request acts as."},{"name":"Domains","description":"Claiming a domain and proving it."},{"name":"Mailboxes","description":"Mailboxes on the account's verified domains."},{"name":"Service tokens","description":"The credentials a program presents. Managed by a signed-in person only."}],"paths":{"/api/accounts/lookup":{"get":{"operationId":"lookUpAccount","tags":["Account"],"security":[{"product":[]}],"summary":"Whether an address or an id is a Praecise account","description":"For the server of a Praecise product that has to check an account it was given. Authenticated with that product's own client id and secret; a person's service token or session is not accepted, and an outside application has no such credential. Give exactly one of `email` and `id`; prefer `id` whenever the caller holds it. Limited to 120 calls a minute for each client, and logged.","x-callers":"The server of any product in the account service's client list.","parameters":[{"name":"email","in":"query","schema":{"type":"string","format":"email"}},{"name":"id","in":"query","schema":{"type":"string","format":"uuid"},"description":"The account's id: `sub` in ID tokens."}],"responses":{"200":{"description":"There is such an account.","content":{"application/json":{"schema":{"type":"object","required":["account"],"properties":{"account":{"type":"object","required":["id","email","confirmed"],"properties":{"id":{"type":"string","format":"uuid","description":"Never changes. Keep this, not the address."},"email":{"type":"string","format":"email"},"confirmed":{"type":"boolean","description":"Whether the person has shown they read that mailbox. When false, do not act for the account on the strength of the address."}}}}}}}},"400":{"description":"Neither or both of `email` and `id` were given, or the value is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No valid client id and secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"This client may not look accounts up (the account service's own client).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No Praecise account has that address, or that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"More than 120 lookups in a minute. `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/me":{"get":{"operationId":"getAccount","tags":["Account"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"Who this request acts as","description":"The cheapest way for a caller to check that a token still works.","responses":{"200":{"description":"The account.","content":{"application/json":{"schema":{"type":"object","required":["account"],"properties":{"account":{"$ref":"#/components/schemas/Account"}}}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/domains":{"get":{"operationId":"listDomains","tags":["Domains"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"The account's domains, and whether each is proven","description":"`records` is what still has to be published. An empty list on an unverified domain means the records are there and DNS has not caught up yet.","responses":{"200":{"description":"The domains.","content":{"application/json":{"schema":{"type":"object","required":["domains"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}}}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"claimDomain","tags":["Domains"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"Claim a domain","description":"Where Praecise holds the registrar for the domain, the ownership record is published and checked in the same call (`published: true`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","examples":["example.com"]}}}}}},"responses":{"201":{"description":"Claimed.","content":{"application/json":{"schema":{"type":"object","required":["domain","verified","published","records"],"properties":{"domain":{"type":"string"},"verified":{"type":"boolean"},"published":{"type":"boolean"},"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}}}}},"400":{"description":"That does not look like a domain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/domains/{domain}/verify":{"post":{"operationId":"verifyDomain","tags":["Domains"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"Check a domain again","description":"Publishes the ownership record again first when Praecise holds the registrar.","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Whether it is verified now.","content":{"application/json":{"schema":{"type":"object","required":["domain","verified"],"properties":{"domain":{"type":"string"},"verified":{"type":"boolean"}}}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/mailboxes":{"get":{"operationId":"listMailboxes","tags":["Mailboxes"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"Every mailbox the account can reach","responses":{"200":{"description":"The mailboxes.","content":{"application/json":{"schema":{"type":"object","required":["mailboxes"],"properties":{"mailboxes":{"type":"array","items":{"$ref":"#/components/schemas/Mailbox"}}}}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createMailbox","tags":["Mailboxes"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"Make a mailbox on a verified domain","description":"The mailbox reads with the Praecise account; it has no password of its own.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["localpart","domain"],"properties":{"localpart":{"type":"string","description":"The part before the @.","examples":["hello"]},"domain":{"type":"string","examples":["example.com"]},"name":{"type":"string","description":"Shown as the sender. The local part when left out."},"kind":{"$ref":"#/components/schemas/Kind"}}}}}},"responses":{"201":{"description":"Made.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Mailbox"}}}},"400":{"description":"The local part is not usable, or `kind` is not one of the three.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"That domain is not on this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"That domain is not verified yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/mailboxes/{email}":{"get":{"operationId":"getMailbox","tags":["Mailboxes"],"security":[{"serviceToken":[]},{"session":[]}],"summary":"One mailbox","parameters":[{"name":"email","in":"path","required":true,"schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"The mailbox.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Mailbox"}}}},"401":{"description":"Neither a service token nor a signed-in session was accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such mailbox on this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The mail service could not be reached, or refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Mail is not configured on this deployment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens":{"get":{"operationId":"listTokens","tags":["Service tokens"],"security":[{"session":[]}],"summary":"The service tokens issued for the account","description":"Never the tokens themselves: what each is called and whether it has been used.","responses":{"200":{"description":"The tokens.","content":{"application/json":{"schema":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenInfo"}}}}}}},"401":{"description":"Nobody is signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A service token was presented. Tokens are managed by a signed-in person, not by another token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"mintToken","tags":["Service tokens"],"security":[{"session":[]}],"summary":"Mint a service token","description":"The only time the token itself is readable. A signed-in person only: a token that could mint its successors would make revoking the original pointless.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80,"examples":["my-service, production"]}}}}}},"responses":{"201":{"description":"Minted.","content":{"application/json":{"schema":{"type":"object","required":["name","token","note"],"properties":{"name":{"type":"string"},"token":{"type":"string","description":"Starts `prc_`. Shown once."},"note":{"type":"string"}}}}}},"400":{"description":"The token needs a name of 1 to 80 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Nobody is signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A service token was presented. Tokens are managed by a signed-in person, not by another token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tokens/{id}":{"delete":{"operationId":"revokeToken","tags":["Service tokens"],"security":[{"session":[]}],"summary":"Revoke a service token","description":"Revoking a token that is already revoked is not an error.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Revoked."},"401":{"description":"Nobody is signed in.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A service token was presented. Tokens are managed by a signed-in person, not by another token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such token on this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"serviceToken":{"type":"http","scheme":"bearer","description":"A service token (`prc_…`), minted by a person on their account page. Acts as that one account."},"session":{"type":"apiKey","in":"cookie","name":"praecise_gateway","description":"A browser signed in at accounts.praecise.com."},"product":{"type":"http","scheme":"basic","description":"A product's own client id and secret at the account service, as at the token endpoint."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"What went wrong, in a sentence."},"detail":{"type":"string"}}},"Account":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string","format":"uuid","description":"Never changes."},"email":{"type":"string","format":"email"}}},"Kind":{"type":"string","enum":["human","agent","machine"],"default":"human","description":"What holds the address: a person, an agent, or a machine."},"DnsRecord":{"type":"object","description":"A DNS record to publish, as the mail service gives it.","additionalProperties":true},"Domain":{"type":"object","required":["domain","verified","records"],"properties":{"domain":{"type":"string"},"verified":{"type":"boolean"},"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"Mailbox":{"type":"object","required":["email","kind","inbox"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":["string","null"]},"kind":{"$ref":"#/components/schemas/Kind"},"inbox":{"type":"boolean","description":"False for a send-only address."}}},"TokenInfo":{"type":"object","required":["id","name","created"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"created":{"type":"string","format":"date-time"},"lastUsed":{"type":["string","null"],"format":"date-time"}}}}}}