How to set up an account through the API
Set up an account through the API when you are moving a firm’s settings into Drum from another system, or building the same setup in several accounts. Each step creates records that a later step refers to by id, so follow the steps in order.
Before you start
You need:
- The setup endpoints turned on for the account. They are in early access. Contact Drum support if a request returns
404 not_found. - An API token of a user whose role has
customisation,read_quotes,create_quotes,update_quotes,read_budgetsandupdate_budgets, and the API permissionsapi_read,api_createandapi_update. An account admin has all of these. See Create an API token. - The members of staff already invited to the account, if rate cards or resource types will name people. Find their ids with
GET /members.
Every example sets these first:
export DRUM_API_TOKEN="your-token"
export DRUM="https://app.getdrum.com/api/v1"
Keep the id of each record a step returns. The setup endpoints do not take an Idempotency-Key, so if a POST times out, check with a GET before you send it again.
1. Read the starting catalog
curl -H "Authorization: Bearer $DRUM_API_TOKEN" "$DRUM/account_settings"
The response lists what the account already has. Check account.name is the account you mean. Note the ids of the two baselines in project_templates (baseline: true): Project Settings and Opportunity Settings. See Read the account catalog.
2. Set project and proposal numbering
-
Set how project numbers are made on Project Settings:
curl -X PATCH "$DRUM/project_settings" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"code": "PRJ", "part_one_generator": "current_year_two_digit", "part_two_generator": "sequential_number_current_year", "code_separator": "-", "number_padding": 3}' - Do the same for opportunities with
PATCH "$DRUM/opportunity_settings". -
Set how proposal numbers are made:
curl -X PATCH "$DRUM/proposal_numbering" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"number_prefix": "Q", "part_one_generator": "current_year_two_digit", "part_two_generator": "sequential_number_current_year", "code_separator": "-", "number_padding": 3}'
The fields are in Change Project Settings or Opportunity Settings and Change proposal numbering.
3. Set statuses and lead scores
Statuses and lead scores are rows of the baselines. Use the baseline ids from step 1. In these examples Project Settings is 640 and Opportunity Settings is 641.
-
Add each project status:
curl -X POST "$DRUM/project_templates/640/statuses" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"name": "In Progress", "colour": "blue"}' - Add each opportunity status to
641, withsales_status_typewonorlostwhere it applies, anddefault_successful_statusordefault_lost_statuson the statuses an opportunity moves to when it is won or lost. -
Add each lead score to
641:curl -X POST "$DRUM/project_templates/641/lead_scores" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"name": "Warm", "percentage": 50}' - Change or delete the statuses the account started with, using their ids from step 1. A baseline keeps at least one status.
See Statuses and Lead scores.
4. Create resource types
Create one resource type for each staff role that is billed. Name the members who bill under it.
curl -X POST "$DRUM/resource_types" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Senior Engineer", "colour": "blue", "default_member_ids": [4821, 4830]}'
See Resource types.
5. Create cost types
curl -X POST "$DRUM/settings/cost_types" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Subcontractor", "default_finance_account_id": 310}'
Find expense account ids with GET /finance_accounts. See Cost types.
6. Create the rate card
Create the account’s rate card with a rate for each resource type from step 4. Add member rates for people who charge a different rate from their role.
curl -X POST "$DRUM/rate_cards" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "2026 rates",
"status": "active",
"effective_date": "2026-07-01",
"is_default": true,
"entries": [
{"rateable_type": "resource_type", "rateable_id": 88, "billable_rate_cents": 18000},
{"rateable_type": "resource_type", "rateable_id": 91, "billable_rate_cents": 12500},
{"rateable_type": "member", "rateable_id": 4821, "billable_rate_cents": 21000}
]
}'
Rates are integer cents, tax exclusive. A rate of 0 needs "allow_zero_value": true. See Rate cards.
7. Create custom fields and add them to the baselines
-
Create each custom field:
curl -X POST "$DRUM/custom_fields" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"label": "Council", "field_type": "select", "options": ["Northern Beaches", "Inner West", "Sutherland"]}' -
Add the field to Project Settings, Opportunity Settings, or both, with an optional default:
curl -X POST "$DRUM/project_templates/640/custom_fields" \ -H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \ -d '{"custom_field_id": 31, "default_value": "Inner West", "primary_filter": true}' -
If the account already has active projects, push the fields to them. This needs
api_deleteas well, because it removes empty fields that no template names:curl -X POST "$DRUM/project_templates/640/sync_custom_fields" \ -H "Authorization: Bearer $DRUM_API_TOKEN"
See Custom fields and the custom field rows.
8. Create project roles, booking types and milestone types
Create the remaining catalogs. Booking types refer to the resource types from step 4.
curl -X POST "$DRUM/project_roles" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Project Lead", "use_case": "project", "permissions": {"view_budgets": true, "update_budgets": true}}'
curl -X POST "$DRUM/booking_types" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Site visit", "default_resource_type_id": 88, "resource_type_ids": [88, 91]}'
curl -X POST "$DRUM/milestone_types" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Handover", "colour": "emerald"}'
See Project roles, Booking types and Milestone types.
9. Create deliverable templates
Create each deliverable template with its tasks and lines in one request. Resource lines use the resource types from step 4, and cost lines the cost types from step 5.
curl -X POST "$DRUM/deliverable_templates" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "Concept design",
"status": "active",
"tasks": [
{
"name": "Site analysis",
"kind": "dynamic",
"resources": [{"resource_type_id": 88, "quantity": 16}],
"costs": [{"cost_type_id": 610, "name": "Survey", "quantity": 1, "billable_rate_cents": 180000}]
},
{"name": "Concept package", "kind": "fixed", "quantity": 1, "quantity_unit": "per_item", "billable_rate_cents": 900000}
]
}'
Check warnings in the response. empty_dynamic_item names dynamic tasks that have no lines and so are worth zero. See Deliverable templates.
10. Create project templates
Create each project template with its phases and deliverables. Give it the rate card from step 6.
curl -X POST "$DRUM/project_templates" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "Residential new build",
"use_case": "project",
"status": "active",
"default_rate_card_id": 95,
"phases": [{"name": "Design", "colour": "blue"}],
"deliverables": [{"deliverable_template_id": 2210, "project_template_phase_name": "Design"}]
}'
Create opportunity templates the same way, with "use_case": "opportunity" and no phases. See Project templates.
11. Create proposal templates
Create each proposal template from its project template. Drum builds its budget from the project template’s deliverables, and a quote section for each.
curl -X POST "$DRUM/proposal_templates" \
-H "Authorization: Bearer $DRUM_API_TOKEN" -H "Content-Type: application/json" \
-d '{
"name": "Residential fee proposal",
"project_template_id": 655,
"default_expiry_days": 30,
"notes": [{"content": "Fees exclude council lodgement charges.", "financial": true}],
"budget": {"rate_card_id": 95}
}'
Then adjust it:
- Change budget rows one at a time under
/proposal_templates/:id/budget/. - Rebuild the quote sections from the budget with
POST /proposal_templates/:id/budget/sync_to_quoteand{"method": "matched"}. This needsapi_deleteas well. - Attach a Word document with
PATCH /proposal_templates/:idandtemplate_document.
See Proposal templates.
12. Check the result
- Read the catalog again with
GET /account_settingsand compare it with your source. - Read each template with its
GETendpoint and checkwarnings. - Open Settings in Drum and check a few templates on screen.