Skip to content

Latest commit

 

History

History
560 lines (434 loc) · 12.9 KB

index.md

File metadata and controls

560 lines (434 loc) · 12.9 KB

Member Services API

All API requests need to be made using secure connections, i.e. with https or wss protocols, and their paths should be prefixed by /api/.

Some GET paths include query parameters. POST body parameters may be included either as application/x-www-form-urlencoded or as application/json. All server responses will be formatted as JSON.

In cases of error, the HTTP status code will be 400 or 401 for client error, and 500 for server error. The response should contain a status field with the contents "error" or "unauthorized", as appropriate, possibly along with some relevant data and/or a message field.


Public information

GET public/people

  • Parameters: csv

List of members who have opted to have their info in public. If the query parameter csv is true-ish, returns results as csv rather than json format.

Response

[
  { country, membership, first_name, last_name },
  …
]

GET public/stats

  • Parameters: csv

Membership statistics by country. If the query parameter csv is true-ish, returns results as csv rather than json format.

Response

{
  Finland: { Adult: 13, …, total: 26 },
  …,
  '': { Adult: 131, …, total: 262 }
}

GET config

The configuration used by this instance.

Response

{
  id: 'w75',
  name: 'Worldcon 75',
  paid_paper_pubs: true,
  membershipTypes: {
    Adult: {
      badge: true,
      hugo_nominator: true,
      member: true,
      wsfs_member: true
    },
    ...
  }
}

Authentication

POST key

  • Parameters: email, name, path, reset

If email matches (case-insensitively) a known address, send a login link to that address. If no key exists or reset is true-ish, generate a new key. If no match is found for email and name is set, create a new non-member account and login key, and send a login link to email. If path is set, it will be included in the login link as the value of the next query parameter.

Response

{
  status: 'success',
  email: '[email protected]'
}

GET/POST login

  • Parameters: email, key

Fails with HTTP status 400 for missing input values, 401 for incorrect email/key combinations, and 403 for expired key (which triggers a key reset and sends an email with an updated login link). Creates a new session object for valid credentials.

Response

Set-Cookie: w75=sessionId

{
  status: 'success',
  email
}

GET/POST logout

  • Requires authentication
  • Parameters: all, reset, email (admin_admin only)

Removes the user information from the current session. If email is set in the parameters, the session user needs admin_admin authority; otherwise it's read from session data. If all is set, all of the user's sessions are terminated. If reset is set, the user's key is also reset, and will need to be re-requested.

Response

{
  status: 'success',
  email,
  opt: undefined | 'all' | 'reset',
  sessions: undefined | #
}

User info

GET user

  • Requires authentication
  • Parameters: email (member_admin only)

If email is not set, its value is read from session data. Returns the memberships matching the given email address, and the roles (e.g. "member_admin") assigned to this email address.

Response

{
  email,
  people: [ { id, membership, legal_name, … }, … ],
  roles: [ … ]
}

GET user/log

  • Requires authentication
  • Parameters: email (member_admin only)

If email is not set, its value is read from session data. Returns the log entries with author set to the given email address.

Response

{
  email,
  log: [ … ]
}

Member info

GET people

  • Requires authentication and member_admin or member_list authority
  • Parameters: since, name, and all person fields

List member data. If no query parameters are present, the response array contains all members and is padded with null values such that response[id].id == id, and fields with null or false values are left out of the response.

since will return entries with a last_modified value (ISO 8601 date) greater than specified. name is shorthand for searching among all three name fields. All text fields are compared using the postgres case-insensitive ILIKE, which uses _ for single-character wildcards and % for multiple characters.

Response

[
  { id, last_modified, member_number, legal_name, email, … },
  …
]

POST people

  • Requires authentication and member_admin authority
  • Parameters: membership, legal_name, email, public_first_name, public_last_name, city, state, country, paper_pubs

Add new person. If membership is not 'NonMember', a new member_number will be generated.

Response

{
  status: 'success',
  id,
  member_number
}

GET people/:id

  • Requires authentication

Find the person matching id. If its email address does not match the session data, member_admin or member_list authority is required.

Response

{
  id, last_modified, member_number, membership, legal_name, email,
  public_first_name, public_last_name, city, state, country,
  paper_pubs: { name, address, country },
  preferred_name, daypass, daypass_days
}

GET people/:id/log

  • Requires authentication

Find the log entries for the person matching id. If its email address does not match the session data, member_admin or member_list authority is required.

Response

[
  { timestamp: …, author: …, subject: …, action: …, … },
  …
]

POST people/:id

  • Requires authentication
  • Parameters: membership (member_admin only), email (member_admin only), legal_name, public_first_name, public_last_name, city, state, country, paper_pubs

Update the data for the person matching id. If its email address does not match the session data, member_admin authority is required.

If set, the paper_pubs value is required to be a JSON object with non-empty values for the fields name, address, and country. If the user does not member_admin authority, it also needs to have been previously set to a non-null value.

Response

{
  status: 'success',
  updated: [ 'legal_name', … ]
}

POST people/:id/upgrade

  • Requires authentication and member_admin authority
  • Parameters: membership, member_number (admin_admin only), paper_pubs

Increase membership level, generating a member_number if not set in parameters or previously set. Also handles paper_pubs purchases, connected or separately from membership changes.

Response

{
  status: 'success',
  member_number,
  updated: [ 'membership', 'member_number', 'paper_pubs' ]
}

POST people/lookup

  • Parameters: email, member_number, name

Finds a person's id, membership and name based on a slightly fuzzy lookup given some subset of the parameters email, member_number, and name. If the lookup matches more than one hit, status will be multiple. If no matches are found, status will be not found. Child and Kid-in-tow members are not included in the results.

Response

{
  status: 'success',
	id,
  membership,
  name
}

WebSocket: people/updates

  • Requires authentication and member_admin authority

WebSocket connection endpoint. The server won't listen to any messages sent to it, but will broadcast updates to People as they happen. Each message will contain as its data a JSON string representation of a single updated person.

The API uses the app-specific codes 4001 and 4004 on WebSocket 'close' events to signal 'Unauthorized' and 'Not Found' (respectively) to the client.

Response

'{"id":#,"member_number":…,"legal_name":…,…}'

Purchases

POST purchase

  • Parameters: account, amount, email, source, new_members: [ { membership, email, legal_name, public_first_name, public_last_name, city, state, country, paper_pubs }, ... ], upgrades: [ { id, membership, paper_pubs }, ... ]

Using the source (or token) object received from Stripe, make a charge of amount on the card (once verified against the server-side calculated sum from the items) and add the new_members to the database as well as applying the specified upgrades. For new members, generate a login key and include it in the welcome email sent to each address. Sends an info message to each new or upgraded member.

Response

{
  status: 'success',
  charge_id
}

GET purchase/data

Current purchase data for non-membership purchases. Top-level keys correspond to pre-defined payment categories and their types. shape values define the shapes of the expected data object, with matching JS type. Shape values with required: true need to have a non-empty value in the matching request.

Response

{
  new_member: {
    label: 'New membership',
    allow_create_account: true,
    shape: [
      {
        key: membership,
        type: string,
        label: 'Membership type'
      },
      ...
    ],
    types: [
      {
        key: 'Adult',
        label: 'Adult',
        amount: 19500
      },
      ...
    ]
  },
  sponsor: {
    label: 'Sponsorship',
    listed: true,
    description: 'Why not sponsor ...',
    shape: [
      {
        key: 'sponsor',
        type: 'string',
        label: 'Sponsor name',
        required: true
      },
      ...
    ],
    types: [
      {
        key: 'bench',
        label: 'Sponsored bench plaque',
        amount: 6000,
        description: '<p>Fannish Tradition ....</p>'
      },
      ...
    ]
  },
  ...
}

GET purchase/keys

Current public Stripe keys. Includes at least the default key. If a non-default key is used, its name should be passed to POST purchase calls as the value of account.

Response

{
  default: 'pk_test_...',
  ...
}

GET purchase/list

Purchases made using this account's email address, or one set as a query parameter (requires member_admin access).

Response

[
  {
    id: 123,
    timestamp: '2017-03-24 06:49:57.229836+00',
    amount: 200000,
    currency: 'eur',
    stripe_charge_id: '...',
    category: 'Sponsorship',
    type: 'bench',
    payment_email: '...',
    person_id: 456,
    person_name: '...',
    data: { sponsor: '...' },
    comments: '...',
    invoice: '456'
  },
  ...
]

POST purchase/other

Parameters:

  • account: Optional, used to set indicate an alternative Stripe account name
  • email: They payer's email address
  • source: { id, ... }: Received from Stripe, used to make the charge
  • items: Array of payment objects, each consisting of:
    • amount, currency: The charge amount, in integer cents of currency
    • person_id, person_name: The beneficiary of the payment (optional)
    • category, type, data: Required to match entries returned by GET purchase/data
    • comments, invoice: Optional strings

Using the source received from Stripe, make a charge on the card or account and adds entries to the Payments table for each item. Sends an info email to each item's beneficiary.

Request

{
  email: '...',
  source: { id: '...' },
  items: [
    {
      amount: 200000,
      currency: 'eur',
      category: 'Sponsorship',
      type: 'bench',
      data: { sponsor: '...' },
      person_id: 123,
      person_name: '...',
      comments: '...',
      invoice: '456'
    }
  ]
}

Response

{
  status: 'succeeded' || 'pending' || 'failed',
  charge_id: '...'
}

Slack

POST slack/invite

Send the user an invitation via email to join the organisation's Slack. Requires the env vars SLACK_ORG and SLACK_TOKEN to be set, with the token having both the client and admin permission scopes granted. Attempting to re-send an invitation will return an error.

Response

{
  success: true,
  email
}