Note that this API is still under development and subject to change

Initial registration

Go to Fermata Control and make a new account and company and generate a new API key.

You’ll need to paste a Stripe API key into the appropriate dialog box. We recommend using a restricted key for security reasons. The only permissions needed for the key are write access to Customers, PaymentIntents, and PaymentMethods.

(Note that initial registration can be completed via API too if needed.)

Authentication

All requests should use HTTP Basic Authentication with the company ID as the username and the API key as the password.

Onboarding Users

New Accounts

When a user registers (or if you just want to import them into our system) you need to make them an account.

Collect name, email address, and billing address from user POST to /companies/{company_id}/accounts endpoint with a payload like this:

{
  "name": "John Smith",
  "email": "john@gofermata.com"
}

If you already have a Stripe account for the customer you can pass the Stripe customer id in the stripe_id parameter. If you leave this off, then we will create a Stripe customer for you in your Stripe account.

We also support a metadata parameter that can be any JSON you want in case you want to track things like your internal customer IDs.

You can pass a plan_id parameter to configure all denominated treasury accounts for the account using a preset configuration. See below for more information on plans.

This API call will return a new account_id starting with a_

Adding a Credit Card

You would still collect payment information using a Stripe.js Card element. The element returns a card token that you then pass into our API via a POST to /accounts/{account_id}/card

The only parameter to pass is token

Creating a balance for an account

You can create balances for your customers in one or more denominations. In most cases a simple “token” denomination will be fine, but multiple denominations can be used to create more complex billing structures. To create a new balance for an account POST to /accounts/{account_id}/balance/{denomination}

Payment Workflow

Note that all USD amounts are in cents so to specify $1 you would put 100 in a USD field. This avoids any issues associated with floating point numbers

Auto-refill

We support time-based and threshold-based auto-refill for each treasury account

PUT /accounts/{account_id}/balance/{denomination}/auto_refill

For time-based:

{
  "amount": 500, // The number of tokens they should get per month
  "usd_charge": 2500, // How much they should be billed for those tokens
  "refill_period": "monthly"
}

Users will be refilled on the same day every month starting today. If the current day is greater than the 28th, their next refill be on the 1st of the second following calendar month and then on the 1st from then on.

For threshold-based:

{
  "amount": 75, // The number of tokens they should get per month
  "usd_charge": 2500, // How much they should be billed for those tokens
  "threshold": 50 // add 50 tokens for \$25 every time the balance drops below 50
}

Checking the user’s balance

GET /accounts/{account_id}/balance/{denomination}

Example response:

{
  "data": {
    "account_id": "a_1234",
    "amount": 100,
    "pending": 0,
    "available": 100,
    "denomination": "token",
    "refill_threshold": 0,
    "refill_amount": 500,
    "refill_usd_amount": 10000,
    "refill_on_day": "5"
  }
}

Billing for an Event

Whenever a billable event occurs, you submit an API call to us to record the event and tell us how much to charge

POST /events

You can pass multiple events in a single call

[
  {
    "type": "AI-PURCHASE",
    "cost_override": {
      "amount": 500,
      "denomination": "token"
    },
    "metadata": {}, // if you have any extra information to record about the event
    "state": "complete"
  }
]

This call always succeeds by default. You can also cause it to fail with a 402 response code if the user’s balance is negative by sending the flag gate_on_balance.

The state field is optional and defaults to complete. It can be used to indicate if an event shouldn’t be fully processed yet by setting it to pending. You can then use PUT /events/{event_id} to set the final state to either complete or cancelled.

A pending event will cause some pending amount to show up in the pending section of the user’s account balance and reflect in the available amount but will not be fully accounted for until changed to complete. If marked cancelled then nothing will be deducted from their account.

Events can only stay in pending for 1 hour and then they will be cancelled automatically.

Pending events can be used to reflect some type of long-running asynchronous operation that a customer is paying for that may or may not fully succeed.

Modifying a Monthly Plan

A plan/refill modification can be schedule for the next month by using the PUT /accounts/{account_id}/auto_refill as described above.

If you want to modify a user’s plan and have it take effect in the middle of the month, then use /accounts/{account_id}/modifymidmonth

{
  "account_id": "a1234",
  "denomination": "token",
  "amount": "1000",
  "usd_charge": "5000"
}

This applies an algorithm whereby the user starts a new monthly plan right away with all the new tokens and all existing tokens are cancelled and they are refunded the prorated amount for those tokens (taken out of the cost of the new plan)

This should only be used to increase a plan. To decrease it doesn’t make sense to do it in the middle of the month so you can use the other endpoint to schedule that decrease for the next month.

Account Plans

As mentioned above, most of the time it makes more sense to create accounts with a plan which creates all needed denominated accounts with the proper settings for the user.

When you make a plan you specify all the different denominations and charges that should be applied to an account and when you make an account you just specify that plan’s id and everything will be configured for you.

As an example of making a plan, here’s something where we would bill the user $10/month for 10GB of storage and 60 minutes of compute time. For every extra GB of storage they get charged $1 and for every extra minute of compute 50 cents.

POST /companies/{company_id}/plan
{
  "name": "Premium Plan",
  "charge_amount": 1000,
  "charge_denomination": "usd",
  "billing_period": "month",
  "overage_charge_mode": "postpay",
  "threshold_alert_percentage": "80",
  "balances": [
    {
      "amount": "10",
      "denomination": "storage-GB",
      "overage_charge_amount": 100,
      "overage_charge_denomination": "USD"
    },
    {
      "amount": "60",
      "denomination": "compute-minute",
      "overage_charge_amount": 50,
      "overage_charge_denomination": "USD"
    }
  ]
}

Webhooks

We support these webhook events:

  • negative_balance: called whenever there is an event for a user that results in a negative balance
  • balance_change: called anytime a user’s balance changes
  • auto_refill: called whenever a refill is triggered automatically (monthly plan renewal for example)
  • threshold: called whenever a customizable threshold is hit for a given account

Registering Webhooks

POST /webhooks
{
  "type": "negative_balance",
  "url": "http://yourwebsite.com/webhook"
}

Both webhooks can go to the same URL

Payload

Webhooks have the following payload:

{
  "company_id": "c_asdf1234", // your company ID
  "callback_id": "cl_98345", // an internal ID for tracking each webhook attempt
  "account_id": "a_34958723", // the ID of the account that triggered the webhook due to an event
  "type": "negative_balance",
  "account_balance": -3700,
  "account_denomination": "token"
}