Integration reference

Get started

Choose your integration, create the right credentials, and make your first request.

1. Choose your integration

System keys, counter keys, and counter license keys are separate credentials. The steps below create a system API key for customer-account integrations.

2. Create your first system API key

  1. Sign in to BottleSpeed as an active Owner or PrimaryOwner of the target system.
  2. Open /application/{systemSlug}/profile and select the Developer tab. The slug is the system name in your application URL, for example north-buffalo.
  3. Choose Permissions: Read for retrieval or Read-Write if the integration creates or changes records.
  4. Choose Expiration: Never, 7 days, 30 days, or 90 days.
  5. Select Generate API key, then Copy API key. The complete secret appears only once. Save it before leaving the result.
  6. Store it in the integration server’s secret storage. Keep it outside browser bundles, source control, and request logs.

API-key permissions do not grant a system role. Customer-account management still requires the creator’s current active Owner/PrimaryOwner membership. An account-specific Owner role is different. Keys also authorize other system APIs allowed for their creator; they have no account-only scope.

Sign in to BottleSpeed →

3. Make your first request

Set SYSTEM_SLUG and API_KEY in your server environment, then request one account page. The base URL is https://bottlespeed.com.

curl --fail-with-body \
  "https://bottlespeed.com/api/system/$SYSTEM_SLUG/customer-account?page=1&pageSize=25" \
  -H "x-api-key: $API_KEY"

An empty system returns:

{
  "customerAccounts": [],
  "pagination": {
    "page": 1,
    "pageSize": 25,
    "totalItems": 0,
    "totalPages": 0,
    "hasPreviousPage": false,
    "hasNextPage": false
  }
}
FieldTypeDetails
x-api-keyrequest headerPreferred system-key header. Alternatively use Authorization: Bearer <system-api-key>. x-api-key takes precedence if both are present.
Content-Typerequest headerapplication/json for requests with a JSON body.

Follow the customer-account reference for populated response objects, pagination, and writes.

Create an API key

POST/api/auth/system/{systemSlug}/api-keys

Create a key for the authenticated user in this system. The first key is created through the signed-in application; this HTTP example uses an existing key.

Authentication: Active system session or an existing Read-Write system API key. All active system roles can manage their own keys; customer-account APIs separately require Owner/PrimaryOwner.

Request

POST /api/auth/system/{systemSlug}/api-keys
x-api-key: <existing-read-write-system-key>
Content-Type: application/json

Path parameters

FieldTypeDetails
systemSlugstring · requiredSlug of the system where the caller is an active member.
FieldTypeDetails
permissionsRead | Read-Write · requiredRead permits GET requests. Read-Write also permits mutations allowed for the owning user.
expiresAtISO timestamp | null · optionalOmit or use null for no expiration. Otherwise a future ISO 8601 timestamp with a timezone; an empty string is invalid.
{
  "permissions": "Read-Write",
  "expiresAt": null
}

Response · 200 OK

{
  "apiKey": "<new-secret-shown-once>",
  "apiKeyRecord": {
    "id": "99999999-9999-4999-8999-999999999999",
    "permissions": "Read-Write",
    "expiresAt": null,
    "createdAt": "2026-09-15T12:00:00.000Z",
    "isExpired": false
  }
}
FieldTypeDetails
apiKeystringFull credential, returned only by creation. Store it securely before closing the result.
apiKeyRecordApiKeyRecordMetadata. id is used to revoke the key; it is not the secret.

See response object fields and error responses.

List your API keys

GET/api/auth/system/{systemSlug}/api-keys

List the authenticated user’s keys for this system. Secrets cannot be recovered from this endpoint.

Authentication: Active system session or a Read/Read-Write system API key.

Request

GET /api/auth/system/{systemSlug}/api-keys
x-api-key: <system-api-key>

Path parameters

FieldTypeDetails
systemSlugstring · requiredSlug of the system where the caller is an active member.

Request body: none.

Response · 200 OK

{
  "apiKeys": [
    {
      "id": "99999999-9999-4999-8999-999999999999",
      "permissions": "Read-Write",
      "expiresAt": null,
      "createdAt": "2026-09-15T12:00:00.000Z",
      "isExpired": false
    }
  ]
}
FieldTypeDetails
apiKeysApiKeyRecord[]Current user’s key metadata, newest first. Empty when no keys exist.

See response object fields and error responses.

Revoke an API key

DELETE/api/auth/system/{systemSlug}/api-keys/{apiKeyId}

Delete one of the authenticated user’s keys in the current system. The secret stops authorizing subsequent requests.

Authentication: Active system session or a Read-Write system API key.

Request

DELETE /api/auth/system/{systemSlug}/api-keys/{apiKeyId}
x-api-key: <read-write-system-key>

Path parameters

FieldTypeDetails
systemSlugstring · requiredSlug of the system where the caller is an active member.
apiKeyIdUUID · requiredapiKeyRecord.id from creation or apiKeys[].id from listing. Must belong to this user and system.

Request body: none.

A missing, already revoked, or other-user key returns 400 with { "error": "API key not found." }. Keys cannot be edited or renewed. Rotate by creating a replacement, updating the integration, then revoking the old key.

Response · 200 OK

{
  "success": true,
  "apiKeyId": "99999999-9999-4999-8999-999999999999"
}
FieldTypeDetails
successbooleantrue after deletion.
apiKeyIdUUIDDeleted key metadata id.

See response object fields and error responses.

Response object fields

ApiKeyRecord

Metadata only; the secret and hash are never included.

FieldTypeDetails
idUUIDKey metadata identifier for revocation.
permissionsRead | Read-WriteMaximum key permission; system role checks still apply.
expiresAtISO timestamp | nullExpiration instant or null for no expiration.
createdAtISO timestampCreation instant.
isExpiredbooleanWhether expiresAt has passed when this response was built.

Error responses

Check the HTTP status before reading success fields. The examples use fictional data. JSON responses can contain null fields; preserve null rather than treating it as an empty string.

FieldTypeDetails
400Bad requestInvalid permissions/expiration, invalid key UUID, or a key not owned by this user in this system.
401UnauthorizedInvalid, expired, revoked or wrong-system key; inactive membership; insufficient system role; or a write with Read permission.
500Server errorUnexpected failure, including malformed JSON. An uncertain write may have completed; reconcile before retrying.

Ordinary error · 400

{
  "error": "API key not found."
}

Validation error · 400

{
  "error": "ValidationError",
  "issues": [
    {
      "code": "custom",
      "path": [
        "expiresAt"
      ],
      "message": "Expiration must be in the future."
    }
  ]
}

error is a string. Validation responses also contain issues, an array with code, path (field names or array indices), and message; other issue fields depend on the validation rule. Missing records use 400 and authorization failures use 401.