IntegrationsGuides

Submitting a MassID

End-to-end guide for submitting a MassID — resolve participants, create the document, add events, and close.

Last updated on

Use this sequence as the base implementation pattern for submitting a complete MassID lifecycle through the Carrot API.

Prerequisites

Before you begin, ensure you have:

  • A registered Network Integrator account with valid API credentials
  • Participant and address data ready — resolve each one first (retrieve by key or create it) so you can reference it by participantId and addressId, as shown in Step 1
  • Familiarity with core concepts — especially the immutable event-sourced model

Submission deadline

Submit mass data as the operation happens. The last cycle that can analyze a batch is the one in the year after its Recycled event, and data has to reach the network by 30 November of that year — a batch recycled in 2025 has until 30 November 2026. The methodology framework rule behind the limit, the cut-off time, and what happens after it are described in Submission window.

Step 1: Resolve participants and addresses

Every document and event needs a participant and an address. Reference them by ID — the form this guide uses — or send the objects inline, which find-or-creates them. Before submitting, resolve each one — look it up by key, or create it — and keep the returned participantId and addressId.

Retrieve by key. Look up an existing participant by its natural key — country code, tax ID type, and tax ID:

GET /participants?countryCode=BR&taxIdType=CNPJ&taxId=11111111111111

If it exists, reuse the returned participantId and list its addresses to find the addressId:

GET /participants/{participantId}/addresses

Create when missing. If the participant does not exist yet, create it, then add an address to it:

POST /participants
{
  "countryCode": "BR",
  "name": "Example Company",
  "taxId": "11111111111111",
  "taxIdType": "CNPJ",
  "type": "COMPANY"
}
POST /participants/{participantId}/addresses
{
  "name": "Main Facility",
  "street": "Rua das Colinas",
  "number": "500",
  "neighborhood": "Centro",
  "city": "São Paulo",
  "countryState": "São Paulo",
  "countryCode": "BR",
  "zipCode": "08575720",
  "latitude": -23.5489,
  "longitude": -46.6388
}

Each create call returns the generated id — use it as participantId / addressId in the next steps. Required fields: participant — countryCode, name, taxId, taxIdType, type; address — city, countryCode, countryState, name, number, street. See the Participants API for the full request and response schema.

Reusing existing records

Creating a participant or address that already exists is safe only if you send identical data — the platform matches on the natural key and rejects conflicting values. Prefer retrieving by key and reusing the returned ID.

Step 2: Create the document

Create the root record with classification and baseline visibility fields, referencing the participant and address you resolved in Step 1:

POST /documents
{
  "category": "MassID",
  "type": "YOUR_WASTE_TYPE",
  "measurementUnit": "kg",
  "externalCreatedAt": "2026-03-01T10:00:00.000Z",
  "isPublic": true,
  "isPubliclySearchable": true,
  "participantId": "participant-id-from-step-1",
  "addressId": "address-id-from-step-1",
  "externalId": "your-internal-tracking-id",
  "deduplicationId": "unique-id-generated-before-first-attempt"
}
FieldRequiredDescription
categoryYesAlways MassID for mass tracking documents
typeYesWaste type — defined per methodology (see note below)
measurementUnitNoDefaults to kg when omitted — send it explicitly. kg is the value both methodologies require
externalCreatedAtYesISO 8601 timestamp of the real-world document creation
isPublicYesWhether the document is publicly visible
isPubliclySearchableYesWhether the document appears in public search
participantIdOne ofID of the participant resolved in Step 1 — send this or an inline participant, never both
addressIdOne ofID of the address resolved in Step 1 — send this or an inline address, never both
externalIdNoYour internal ID for reconciliation — useful for mapping back to your system
deduplicationIdNoIdempotency key — see tip below

Inline participant and address

You can send full participant and address objects inline instead of participantId/addressId; the platform find-or-creates them. Send exactly one of each pair — both, or neither, fails validation with 400 VALIDATION_ERROR. Prefer resolving in Step 1 and referencing by ID; the inline form is the only way to create a document together with a new participant or address in a single call.

Methodology-specific values

The type field (waste type) and measurementUnit are defined by your target methodology. See the methodology integration guides for the specific values required. A MassID is measured in kg under both BOLD Recycling and BOLD Carbon — the rule set rejects any other value. kg CO₂e is the unit of the emission reductions the methodology calculates from that mass, not the unit of the MassID itself.

Reference: Documents API.

Step 3: Append timeline events

Append events in chronological order to represent operational steps. Each event is immutable once created.

ACTOR events

ACTOR events register participant roles on the document timeline. Each requires a label identifying the role, plus the participant and address it applies to, referenced by ID:

POST /documents/{documentId}/events
{
  "name": "ACTOR",
  "label": "YOUR_ROLE_LABEL",
  "externalCreatedAt": "2026-03-01T10:05:00.000Z",
  "isPublic": true,
  "participantId": "actor-participant-id",
  "addressId": "actor-address-id"
}

The label value (e.g. "Waste Generator", "Hauler", "Processor") is defined by each methodology. See your methodology guide for the required roles and their labels.

Resolve each actor's participant and address the same way as in Step 1, then reference them by participantId and addressId.

CUSTOM events

CUSTOM events represent methodology-specific operational steps. The event name, required metadata attributes, and sequence are all defined by the methodology:

POST /documents/{documentId}/events
{
  "name": "YOUR_EVENT_NAME",
  "externalCreatedAt": "2026-03-01T11:00:00.000Z",
  "isPublic": true,
  "participantId": "participant-id-from-step-1",
  "addressId": "address-id-from-step-1",
  "metadata": {
    "attributes": [
      { "name": "YOUR_ATTRIBUTE_NAME", "value": "attribute-value", "isPublic": true }
    ]
  },
  "value": 150.5
}

The value field on events contributes to the document's currentValue. For example, a weighing event with value: 150.5 sets the tracked weight.

Inline participant and address

Events accept the same inline participant and address objects as documents, with the same find-or-create behavior. Prefer referencing participantId and addressId.

Methodology guides

Each methodology defines the specific event sequence, event names, and required metadata attributes. See the methodology integration guides for the values required by each methodology.

Document status lifecycle

Documents follow a strict status lifecycle:

  • OPEN — Default status after creation. Events can be appended freely.
  • CLOSE event — Transitions the document to CLOSED. After closing, only RELATED and CANCEL events are accepted — CANCEL survives CLOSE precisely so the CANCEL-and-recreate pattern stays available on a closed document.
  • CANCEL event — Transitions the document to CANCELLED. No further events are accepted.

Send a CLOSE event when the supply chain lifecycle is complete:

POST /documents/{documentId}/events
{
  "name": "CLOSE",
  "externalCreatedAt": "2026-03-02T16:00:00.000Z",
  "isPublic": true,
  "participantId": "integrator-participant-id",
  "addressId": "integrator-address-id"
}

See Event Specification for the full list of event categories.

Reference: Events API.

For high-volume integrations, consider the batch events endpoint to submit multiple events per request.

Step 4: Attach evidence files (optional)

Some methodology rules require evidence attachments (e.g. scale tickets, transport manifests). The pattern is:

  1. Request a pre-signed upload URL via the Attachments API
  2. Upload the file directly to the pre-signed URL
  3. Reference the attachment in the relevant event's attachments array

Attachments are linked to specific events, not to the document as a whole. This ensures each piece of evidence is tied to the operational step it documents.

Reference: Attachments API.

Step 5: Retrieve and validate final state

Fetch the document and verify before considering the submission complete:

  • Event count and ordering — all expected events are present in chronological order
  • Status is CLOSED — the document has been properly closed
  • currentValue > 0 — the document has a positive tracked value
  • At least one ACTOR event — the required participant roles are registered
  • Participant and address links — all references resolve correctly
  • Metadata completeness — required attributes are present on each event per the methodology

Reference: GET document by ID.

Operational tips

deduplicationId

Always send deduplicationId on retryable write calls (document creation and event creation). Generate a unique ID before the first attempt, store it, and reuse the same ID on every retry. The ID is scoped per integrator — two different integrators can use the same ID without conflict. A replayed ID is rejected with 409 CONFLICT_ERROR, never replayed: treat that conflict as confirmation that the first attempt succeeded and no duplicate was created. The response does not return the original document id, and no endpoint looks a document up by externalId or deduplicationId — so record the id from the first successful response, and treat a lost POST /documents response as a support request.

  • Use externalId on documents and events for reconciliation with your internal systems.
  • Treat 4xx as data/integration issues and 5xx as transient failures — see Error Handling.
  • Plan backfills to land before the 30 November cut-off — see Submission window.
  • Keep your source timestamp strategy deterministic — see Data Formats.

On this page